HasQueryFilter
- это обобщенный c метод, в котором обобщенный c параметр T
соответствует параметру предыдущего вызова Entity<EntityType>
. У вас нет проблем с передачей выражения вручную , когда используются соответствующие типы. Однако свойство выражения, которое вы пытались передать, имеет тип Expression<Func<ISoftDelete, bool>>
, и не существует неявного преобразования из Expression<Func<EntityType, bool>>
, даже если 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):
}
И затем вы можете сослаться на это внутри вашего фильтра запросов:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Epic>().HasQueryFilter(SoftDeleteHelper<Epic>.ExcludeSoftDeleted);
modelBuilder.Entity<Feature>().HasQueryFilter(SoftDeleteHelper<Feature>.ExcludeSoftDeleted);
modelBuilder.Entity<UserStory>().HasQueryFilter(SoftDeleteHelper<UserStory>.ExcludeSoftDeleted);
}
Ключевым моментом здесь является то, что мы ограничили параметр generi c значением ISoftDelete
, который гарантирует, что свойство DeletedOn
существует для типа сущности.
В качестве альтернативы вы можете определить это как метод, который возвращает выражение вашей сущности. Это может быть более подходящим, если у вас есть другие фильтры запросов, которые необходимо ограничить различными интерфейсами:
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>())
Вы можете go сделать шаг вперед и написать методы расширения для ModelBuilder
или EntityTypeBuilder<T>
, ограниченные обобщенным значением c введите и опустите вспомогательный класс в целом
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
);
}
}
Это снова работает благодаря ограничению c generic ISoftDelete
. Затем вы можете вызвать их как:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Epic>().WithSoftDelete();
// or
modelBuilder.EntityWithSoftDelete<Feature>();
}
Методы возвращают EntityTypeBuilder<T>
, который затем можно использовать для объединения дальнейших конфигураций сущностей.