C# 将泛型func作为Linq表达式C传递#
我有一个Linq表达式,它在多个地方重复。我想集中定义Linq表达式,并在所有这些地方使用它。代码如下:C# 将泛型func作为Linq表达式C传递#,c#,linq,C#,Linq,我有一个Linq表达式,它在多个地方重复。我想集中定义Linq表达式,并在所有这些地方使用它。代码如下: public interface ISoftDelete { DateTime? DeletedOn { get; set; } } public class BaseModel : ISoftDelete { public int Id { get; set; } public DateTime? DeletedOn { get; set; } }
public interface ISoftDelete
{
DateTime? DeletedOn { get; set; }
}
public class BaseModel : ISoftDelete
{
public int Id { get; set; }
public DateTime? DeletedOn { get; set; }
}
public class Epic: BaseModel {
}
public class Feature: BaseModel {
}
public class UserStory: BaseModel {
}
public class ProductFocusDbContext : DbContext
{
public ProductFocusDbContext(DbContextOptions<ProductFocusDbContext> options) : base(options) { }
public DbSet<Epic> Epics { get; set; }
public DbSet<Feature> Features { get; set; }
public DbSet<UserStory> UserStories { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Epic
modelBuilder.Entity<Epic>().HasQueryFilter(ExcludeSoftDeleted);
// Feature
modelBuilder.Entity<Feature>().HasQueryFilter(x => x.DeletedOn == null);
// User Story
modelBuilder.Entity<UserStory>().HasQueryFilter(x => x.DeletedOn == null);
}
System.Linq.Expressions.Expression<Func<ISoftDelete, bool>> ExcludeSoftDeleted = (x => x.DeletedOn == null) ;
}
公共接口ISoftDelete
{
DateTime?DeletedOn{get;set;}
}
公共类基类:ISoftDelete
{
公共int Id{get;set;}
公共日期时间?DeletedOn{get;set;}
}
公共类史诗:基本模型{
}
公共类特性:BaseModel{
}
公共类UserStory:BaseModel{
}
公共类ProductFocusDbContext:DbContext
{
public ProductFocusDbContext(DbContextOptions选项):基本(选项){}
公共数据库集Epics{get;set;}
公共数据库集功能{get;set;}
公共数据库集用户故事{get;set;}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
//史诗
modelBuilder.Entity().HasQueryFilter(不包括已删除的软件);
//特征
modelBuilder.Entity().haskqueryfilter(x=>x.DeletedOn==null);
//用户故事
modelBuilder.Entity().haskqueryfilter(x=>x.DeletedOn==null);
}
System.Linq.Expressions.Expression ExcludeSoftDeleted=(x=>x.DeletedOn==null);
}
我想用ExcludeSoftDeleted替换所有出现的x=>x.DeletedOn==null
,但当我尝试使用上述代码执行此操作时,会出现以下异常:
InvalidOperationException:筛选器表达式“x=>(x.DeletedOn==
为实体类型“Epic”指定的“”无效。表情
必须接受类型为的单个参数
“ProductFocus.Domain.Model.Epic”,返回bool,并且可能不包含
对导航属性的引用
我怎样才能做到呢
haskqueryfilter
是一种通用方法,其中通用参数T
与先前调用实体的参数匹配。在使用适当的类型时,手动传递表达式没有问题。但是,您尝试传递的表达式属性的类型为expression
,并且没有从expression
进行隐式转换,即使EntityType
实现了ISoftDelete
(expression
不是协变的),这就是它不起作用的原因
您可以通过提供一些帮助器类来解决这个问题,这些帮助器类可以为您的实体返回适当的表达式
public static class SoftDeleteHelper<T>
where T: ISoftDelete // constrain generic type to interface
{
public static Expression<Func<T, bool>> ExcludeSoftDeleted
=> (x => x.DeletedOn == null):
}
然后可以像下面那样使用(注意这与上面不同,需要调用返回表达式而不引用属性的函数时使用()
)
由于ISoftDelete
上的通用约束,此功能再次发挥作用。然后你可以这样称呼他们:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Epic>().WithSoftDelete();
// or
modelBuilder.EntityWithSoftDelete<Feature>();
}
模型创建时受保护的覆盖无效(ModelBuilder ModelBuilder)
{
modelBuilder.Entity().WithSoftDelete();
//或
modelBuilder.EntityWithSoftDelete();
}
这些方法返回一个EntityTypeBuilder
,您可以使用它来链接进一步的实体配置。A在这里很有用。好的,我将尝试创建一个最小的代表。示例我用一个最小的可重复示例更新了我的问题它不可重复。我不能复制、粘贴和编译,更不用说运行了。理想情况下,我希望运行它,但至少要编译它。请将您的代码复制到一个新的控制台应用程序中,并让它编译/运行。谢谢@pinkfloydx33,这是我尝试过的,它成功了。如果您可以抽出一些时间来回答这个问题,如果您可以,请解释一下为什么接口类型不起作用,而我必须使用具体类型来生成有效的Linq表达式。谢谢
public static class ExpressionHelper
{
public static Expression<Func<T, bool>> ExcludeSoftDeleted<T>()
where T: ISoftDelete // constrained to interface
=> (x => x.DeletedOn == null);
}
modelBuilder.Entity<Epic>().HasQueryFilter(ExpressionHelper.ExcludeSoftDeleted<Epic>())
public static class EntityBuilderExtensions
{
// extension method on the main builder
public static EntityTypeBuilder<T> EntityWithSoftDelete<T>(
this ModelBuilder builder)
where T: class, ISoftDelete // extra class constraint required by Entity<>
{
return builder.Entity<T>().WithSoftDelete();
}
// extension method on the result of Entity<T>
public static EntityTypeBuilder<T> WithSoftDelete<T>(
this EntityTypeBuilder<T> builder)
where T: class, ISoftDelete // extra class constraint required by Entity<>
{
return builder.HasQueryFilter(
e => e.DeletedOn == null
);
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Epic>().WithSoftDelete();
// or
modelBuilder.EntityWithSoftDelete<Feature>();
}