【问题标题】:Default Clasure Where in Includes Generyc Repository Entity Framework 6.1 Code First c#Default Clasure Where in Includes Generyc Repository Entity Framework 6.1 Code First c#
【发布时间】:2016-02-02 14:27:52
【问题描述】:

我有一个通用存储库,其中所有数据库表都有一个要删除逻辑的列。例如:

View my simple database diagram

我需要将存储库持有的 Sale 表中的所有查询添加到条件否定删除列,包括何时包含表(SaleItem、Item、Customer)。

[Table("Sale")]
public partial class Sale
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Sale()
    {        
        SaleItems = new HashSet<SaleItem>();            
    }

    public long ID { get; set; }
    public long? CostumerID { get; set; }
    public virtual Costumer Costumer { get; set; }
    public bool Deleted { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<SaleItem> SaleItems { get; set; }

public class SaleRepository : BaseRepository<Sale>
{
    public async Task<Sale> FindOneAndRelatedAsync(object id)
    {
        return await FindAsync(id,
            (s => s.Costumer),
            (s => s.SaleItems),
            (s => s.SaleItems.Select(si => si.Item))
        );
 }

public class BaseRepository<T> : IBaseRepository<T> where T : class
{
    private string deletedName = "Deleted";
    public async virtual Task<T> FindAsync(object id, params Expression<Func<T, object>>[] includes)
    {
        return await FindAsync(id, false, includes);
    }

    public async virtual Task<T> FindAsync(object id, bool hasDeleted = false, params Expression<Func<T, object>>[] includes)
    {
        var query = DbSet.AsQueryable();

        query = includeRelationships(includes, query);

        query = query.Where(idPredicateExpression(id));

        if (!hasDeleted)
            query = query.Where(deletedPredicateExpression());

        return await query.FirstOrDefaultAsync();
    }

    protected Expression<Func<T, bool>> deletedPredicateExpression()
    {
        return columnPredicateExpression(deletedName, false);
    }

    protected Expression<Func<T, bool>> columnPredicateExpression(string columnName, object keyword)
    {
        var arg = Expression.Parameter(typeof(T), "p");

        var method = keyword.GetType() == typeof(string) ? typeof(string).GetMethod("Contains", new[] { typeof(string) }) : keyword.GetType().GetMethod("Equals", new[] { keyword.GetType() });

        var body = Expression.Call(
            Expression.Property(arg, columnName),
            method,
            Expression.Constant(keyword));

        return Expression.Lambda<Func<T, bool>>(body, arg);
    }

    protected IQueryable<T> includeRelationships(Expression<Func<T, object>>[] includes, IQueryable<T> query)
    {
        if (includes != null)
        {
            query = includes.Aggregate(query, (current, include) => current.Include(include));
        }

        return query;
    }

从上面的代码中可以看出,我可以创建一个表达式来使用 deletedPredicateExpression() 方法为 Sale 实体添加条件 WHERE。它完美地工作。但是 includeRelationships() 方法包含的实体(SaleItem、Item 和 Costumer)必须包含条件 WHERE

当关系为 1:n 时,作为 Costumer 实体。我可以执行插入下面的代码。

    protected IQueryable<T> includeRelationships(Expression<Func<T, object>>[] includes, IQueryable<T> query)
    {
        if (includes != null)
        {
            int i = 0;
            query = includes.Aggregate(query, (current, include) => current.Include(include));
            foreach (var include in includes)
            {
                    var test = test(include.Body.Type);
                    query = query.Where(test).AsQueryable();
            }

        }

        return query;
    }

    protected Expression<Func<T, bool>> test(Type typeEntity)
    {
        string columnName = typeEntity.Name +"." + deletedName;

            string[] props = columnName.Split('.');
            Type type = typeof(T);
            ParameterExpression arg = Expression.Parameter(type, "m");
            Expression expr = arg;
            foreach (string prop in props)
            {
                // use reflection (not ComponentModel) to mirror LINQ
                PropertyInfo pi = type.GetProperty(prop);
                expr = Expression.Property(expr, pi);
                type = pi.PropertyType;
            }
            var val1 = Expression.Constant(false);
            Expression e1 = Expression.Equal(expr, val1);
            Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
            return (Expression<Func<T, bool>>)Expression.Lambda(delegateType, e1, arg);  
    }

如果我的关系是 N:N,或者当我需要访问集合内的对象时,例如在 SaleItems 下的实体 Item 中,则不能包含子句 WHERE 因为它没有对象 SaleItemsItem 的属性 Deleted

是否存在过滤所有实体以始终生成查询的方法,考虑到默认情况下 WHERE Deleted == 0 的情况?

【问题讨论】:

    标签: generics c#-4.0 lambda ef-code-first repository-pattern


    【解决方案1】:

    创建一个包含删除状态属性的基础实体。然后,从这个基础实体继承你的所有类。因此,您可以使用Where 在任何地方进行过滤。

    public abstract class BaseEntity
    {
        public BaseEntity()
        {
            IsDelete = false;
        }
        [Key]
        public int Id { get; set; }
    
       public bool IsDelete { get; set; }
    }
    
    public class Yourclass : BaseEntity // Sale class or somethingelse
    {
      //
    }
    

    并且你需要使用这个BaseEntity 类作为主类,而不是class 用于泛型T 类。

    public class BaseRepository<T> : IBaseRepository<T> where T : BaseEntity
    {
       public T GetById(int id)
        {
            return this.Entities.Single(item => item.Id == id && !item.IsDelete);            
    
        }
        // implement your methods here by using IsDelete property in `Where`          condition.
    }
    

    使用这个BaseEntity作为主要实体类,即使在集合中,您也可以通过删除状态过滤所有类。

    【讨论】:

      猜你喜欢
      • 2016-01-30
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      相关资源
      最近更新 更多