C# 将泛型func作为Linq表达式C传递#

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; } }

我有一个Linq表达式,它在多个地方重复。我想集中定义Linq表达式,并在所有这些地方使用它。代码如下:

 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>();
}