C# 将Linq重用到实体';表达式<;Func<;T、 TResult>;在Select和Where调用中
假设我有一个实体对象定义为C# 将Linq重用到实体';表达式<;Func<;T、 TResult>;在Select和Where调用中,c#,linq,delegates,lambda,C#,Linq,Delegates,Lambda,假设我有一个实体对象定义为 public partial class Article { public Id { get; set; } public Text { get; set; } public UserId { get; set; } } 根据文章的某些属性,我需要确定给定用户是否可以删除该文章。因
public partial class Article
{
public Id
{
get;
set;
}
public Text
{
get;
set;
}
public UserId
{
get;
set;
}
}
根据文章的某些属性,我需要确定给定用户是否可以删除该文章。因此,我添加了一个静态方法来进行检查。比如:
public partial class Article
{
public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
{
//Add logic to be reused here
return a => a.UserId == userId;
}
}
using(MyEntities e = new MyEntities())
{
//get the current user id
int currentUserId = 0;
e.Articles.Select(a => new
{
Text = a.Text,
CanBeDeleted = ???
};
}
到目前为止还不错。现在我想在执行Select时重用CanBeDeletedBy中的逻辑,例如:
public partial class Article
{
public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
{
//Add logic to be reused here
return a => a.UserId == userId;
}
}
using(MyEntities e = new MyEntities())
{
//get the current user id
int currentUserId = 0;
e.Articles.Select(a => new
{
Text = a.Text,
CanBeDeleted = ???
};
}
但是无论我尝试什么,我都不能在select方法中使用表达式。我想如果我能做到的话
e.Articles.Select(a => new
{
Text = a.Text,
CanBeDeleted = a => a.UserId == userId
};
那么我应该可以使用相同的表达式。尝试编译表达式并通过执行以下操作调用它
e.Articles.Select(a => new
{
Text = a.Text,
CanBeDeleted = Article.CanBeDeletedBy(currentUserId).Compile()(a)
};
但这也行不通
你有什么办法让它发挥作用吗?或者如果不可能,在这两个地方重用业务逻辑的替代方案是什么
谢谢
佩德罗重复使用表达式树是一门黑色艺术;您可以这样做,但是您需要将大量代码切换到反射,这样您将丢失所有的静态检查。特别是,使用匿名类型成为一场噩梦(尽管4.0中的
dynamic
可能是可行的)
此外,如果您作弊并使用Expression.Invoke
,则并非所有提供程序都支持它(最明显的是,并非在.NET3.5SP1中的EF上)
除非这是一个主要的痛点,否则我会让它重复。或者您需要重新使用表达式树吗?我所做的是使用PredicateBuilder,它是LinqKit中的一个类,也是一个expandable()来构建表达式,并将它们静态存储为
public readonly Expression<Func<T,bool>>
公共只读表达式
在静态类中。每个表达式都是在前一个表达式的基础上构建的,因此减少了重复的数量
正如马克·格雷威尔(Marc Gravell)提出的上一个问题所指出的那样,这类事情是一种黑色艺术,但谢天谢地,其他人做了很多工作。编译表达式是正确的选择,它为我编译并工作。如果是我的话,我也会把汇编工作考虑在内。您遇到了什么错误?是的,它编译得很好,但引发了NotSupportedException异常:“LINQ to Entities中不支持LINQ表达式节点类型'Invoke'。尝试将Select外部的表达式编译成Func并在内部使用,结果相同。顺便说一句,如果我使用普通Func,并在Where方法中使用它,然后查询将在客户机上执行,这不是预期的目的。啊,对不起,我的错误-错过了使用EF的事实-它可以与linq to对象一起工作:)不需要重新使用表达式树。这只是为了避免重复与安全相关的代码。但我现在会做,看看以后是否可以重构代码。谢谢