实体框架IsDeleted或IsDisabled列

时间:2015-08-12 18:36:12

标签: c# sql-server entity-framework

我从不想删除某些表中的行,所以我添加了一个IsDeleted列。

代表这些表的POCS都实现了IDeleteable接口。

当我做类似的事情时 -

foreach (ITransactionItem transactionItem in Transaction.TransactionItemCollection.AsEnumerable().ToList())
                {
                    ITransactionItem transactionItemModel = new TransactionItemModel();
                    transactionItemModel.CopyFrom(transactionItem);

                    transactionItem.PickUpQuantity = 0;
                    transactionItem.IsPickUp = false;
                    this.PickUpItemCollection.Add(transactionItemModel);
                }

我想回到没有设置IsDeleted位的行。

我不想将context.Users.Where(u => u.Firstname == "Dave") 添加到&& IsDeleted == false

我还希望此解决方案适用于WhereSingleFirst

我想要解决这个问题question

2 个答案:

答案 0 :(得分:2)

根据下面的trailmax评论,是的,下面的原始答案确实将所有数据加载到内存中,因为它暴露了链式枚举。

尝试将IQueryable个调用链接在一起时会出现两个问题。

  1. EF不知道如何翻译生成的.Invoke()来电
  2. 如果您尝试维护.Where()之类的命名约定,则最终会选择错误的扩展名,因为IDeletable只会公开一个可以构建谓词的列。
  3. 以下内容依赖于LinqKit库来链表达式,语法不再流畅,但它确实避免了立即执行。

    var users = context.Users.WhereIsNotDeleted(x => x.Id > 0).ToList();
    
    public static class Extension
    {
        public static IEnumerable<T> WhereIsNotDeleted<T>(this IQueryable<T> source,
            Expression<Func<T, bool>> predicate) where T : IDeletable
        {
            var query = source.AsExpandable().Where(x => !x.IsDeleted);
            return query.Where(predicate);
        }
    }
    

    假设IDeletable保证存在IsDeleted,您可以创建一个始终为您执行此检查的扩展方法。

    public interface IDeletable
    {
        bool IsDeleted { get; set; }
    }
    
    public static class Extension
    {
        public static IEnumerable<T> WhereNotDeleted<T>(this IEnumerable<T> source, 
            Func<T, bool> predicate) where T : IDeletable
        {
            return source.Where(x => !x.IsDeleted).Where(predicate);
        }
    }
    

    在下面的简单测试中,只返回了两条记录,因为第三条记录已被软删除。

    void Main()
    {
        var x = new List<Test>();
    
        x.Add(new Test{ Number = "one" });
        x.Add(new Test{ Number = "two" });
        x.Add(new Test{ Number = "three", IsDeleted = true });
    
        var y = x.WhereNotDeleted(a => a != null);
        y.Count().Dump();
    }
    
    public class Test : IDeletable
    {
        public string Number { get; set; }
        public bool IsDeleted { get; set; }
    }
    

    根据您的评论,如果您希望它与EXISTING LINQ扩展方法一起使用,您实际上无法实现,因为您遇到了调用歧义。

    如果您想调用.Where()并将其转换为您的条件仅适用于实现IDeletable的对象,则需要包装每个LINQ扩展方法。

    public static class Extension
    {
        public static IEnumerable<IDeletable> Where(this IEnumerable<IDeletable> source, 
            Func<IDeletable, bool> predicate)
        {
            return System.Linq.Enumerable.Where(source, (x => predicate(x) && !x.IsDeleted));
        }
    }
    

    在这些扩展方法中,您必须通过实例调用而不是作为扩展方法调用基本LINQ方法,否则您将遇到堆栈溢出异常。

答案 1 :(得分:0)

您可以为每个具有where子句作为其过滤器的表创建一个视图。然后,您可以从实体框架而不是基础表访问该视图,而不用担心它。您的用户永远不会知道基础表,只知道视图。