我们有以下内容:
public interface IOne {
UInt64 Id { get; }
Int16 Size { get; }
}
public interface ITwo {
UInt64 OneId { get; }
Int16 Color { get; }
}
正如here所解释的那样,重用linq表达式的方法是编写如下内容:
public static Expression<Func<IOne, bool>> MyWhereExpression( int value ){
return (o) => (o.Size > value);
}
int v = 5;
IQueryable<IOne> records = from one in s.Query<IOne>()
.Where(MyWhereExpression(v))
select one;
当我想对两张桌子做同样的事情时,我遇到了问题。
表达式:
public static Expression<Func<IOne, ITwo, bool>> MyWhereExpression2(int color ) {
return (one,two) => (one.Id == two.OneId) && (two.Color > color );
}
Linq 1:
int color = 100;
IQueryable<IOne> records = from one in s.Query<IOne>()
from two in s.Query<ITwo>()
.Where(MyWhereExpression2(color))
select one;
这不能用作。只能从中仅限于第二个。
Linq 2:
int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
from two in s.Query<ITwo>()
select new { one, two })
.Where(MyWhereExpression2(color));
这导致
参数2:无法转换为'Expression&lt; System.Func&lt; IOne,ITwo,bool&gt;&gt;' 到'System.Func&lt; AnonymousType#1,int,bool&gt;'
我理解有关AnonymousType的错误消息,但我无法弄清楚如何编写查询。
我想使用表达式而不是只写
的原因where (one.Id == two.OneId) && (two.Color > color )
直接在linq查询中是因为我想在多个linq查询中重用此表达式。
答案 0 :(得分:3)
目前可能有一个更优雅的解决方案让我感到厌烦,但您可以使用Tuple<IOne, ITwo>
而不是匿名类型:
static Expression<Func<Tuple<IOne, ITwo>, bool>> MyWhereExpression2(int color) {
return t => (t.Item1.Id == t.Item2.OneId) && (t.Item2.Color > color);
}
int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
from two in s.Query<ITwo>()
select Tuple.Create(one, two))
.Where(MyWhereExpression2(color))
.Select(t => t.Item1);
更新: 上面的回答太快了,因为对Tuple.Create的调用无法转换为SQL,因此无法使用Linq to SQL。要使用Linq to SQL,我目前看到的唯一解决方案是创建一个命名类型:
class Pair
{
public IOne One { get; set; }
public ITwo Two { get; set; }
}
static Expression<Func<Pair, bool>> MyWhereExpression2(int color) {
return p => (p.One.Id == p.Two.OneId) && (p.Two.Color > color);
}
int color = 100;
IQueryable<IOne> records = (from one in s.Query<IOne>()
from two in s.Query<ITwo>()
select new Pair { One = one, Two = two })
.Where(MyWhereExpression2(color))
.Select(p => p.One);
答案 1 :(得分:1)
首先,为什么你有两个具有相同字段集的表?理想情况下,数据库设计应避免使用不同表中的相同字段名设计应该使用继承。公共字段应该移动到基类中,EF允许您为每个层次结构创建表,这应该可以解决您的问题。
如果使用Table Per Hierarchy创建模型,那么您将不需要接口,并且您的linq查询可以使用共享过滤器表达式。
除非您坐下来编写一个复杂的基于反射的方法,将表达式从一种类型克隆到另一种类型,否则无法实现您的要求。
答案 2 :(得分:1)
回答我自己的问题......
经过一些实验(包括Nick Guerrera的原始答案)后,我采取了另一种方法 - 而不是尝试重用表达式,我重用了整个linq。但是,它仍然需要创建容器结构。
struct Pair {
public IOne One { get; set; }
public ITwo Two { get; set; }
public Pair(IOne one, ITwo two) : this() {
One = one;
Two = two;
}
}
public IQueryable<Pair> Get(ISession s, int color) {
return from one in s.Query<IOne>()
from two in s.Query<ITwo>()
where (one.Id == two.OneId) && (two.Color > color)
select new Pair(one, two);
}
现在我可以致电
Get(s, color).Count();
和
var records = (from data in Get(s, color) select data).Take(2000);
等