代码之家  ›  专栏  ›  技术社区  ›  Ali Ersöz

比较Linq和Sql中的可空类型

  •  40
  • Ali Ersöz  · 技术社区  · 15 年前

    这里有什么问题,我错过了什么?

    public IEnumerable<ICategory> GetSubCategories(long? categoryId)
    {
        var subCategories = this.Repository.Categories.Where(c => c.ParentId == categoryId)
            .ToList().Cast<ICategory>();
    
        return subCategories;
    }
    

    7 回复  |  直到 15 年前
        1
  •  54
  •   ariel    14 年前

    其他方式:

    Where object.Equals(c.ParentId, categoryId)
    

    Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)
    
        2
  •  29
  •   Marc Gravell    15 年前

    要做的第一件事是进行日志记录,查看生成了什么TSQL;例如:

    ctx.Log = Console.Out;
    

    LINQ to SQL似乎对null的处理有点不一致(取决于文字与值):

    using(var ctx = new DataClasses2DataContext())
    {
        ctx.Log = Console.Out;
        int? mgr = (int?)null; // redundant int? for comparison...
        // 23 rows:
        var bosses1 = ctx.Employees.Where(x => x.ReportsTo == (int?)null).ToList();
        // 0 rows:
        var bosses2 = ctx.Employees.Where(x => x.ReportsTo == mgr).ToList();
    }
    

    Expression<Func<Category,bool>> predicate;
    if(categoryId == null) {
        predicate = c=>c.ParentId == null;
    } else {
        predicate = c=>c.ParentId == categoryId;
    }
    var subCategories = this.Repository.Categories
               .Where(predicate).ToList().Cast<ICategory>();
    

    Expression :

        static void Main()
        {
            ShowEmps(29); // 4 rows
            ShowEmps(null); // 23 rows
        }
        static void ShowEmps(int? manager)
        {
            using (var ctx = new DataClasses2DataContext())
            {
                ctx.Log = Console.Out;
                var emps = ctx.Employees.Where(x => x.ReportsTo, manager).ToList();
                Console.WriteLine(emps.Count);
            }
        }
        static IQueryable<T> Where<T, TValue>(
            this IQueryable<T> source,
            Expression<Func<T, TValue?>> selector,
            TValue? value) where TValue : struct
        {
            var param = Expression.Parameter(typeof (T), "x");
            var member = Expression.Invoke(selector, param);
            var body = Expression.Equal(
                    member, Expression.Constant(value, typeof (TValue?)));
            var lambda = Expression.Lambda<Func<T,bool>>(body, param);
            return source.Where(lambda);
        }
    
        3
  •  5
  •   Eric Petroelje    15 年前

    我的猜测是,这是由于DBMS的一个相当常见的属性——仅仅因为两个东西都为null并不意味着它们相等。

    要详细说明一下,请尝试执行以下两个查询:

    SELECT * FROM TABLE WHERE field = NULL
    
    SELECT * FROM TABLE WHERE field IS NULL
    

    当您显式检查“field==NULL”时,LINQ可能会将其转换为“fieldisnull”。但是当您使用变量时,我猜LINQ不会自动进行转换。

    这是 an MSDN forum post 有关此问题的更多信息。

    c => c.ParentId.Equals(categoryId)
    
        4
  •  4
  •   algreat    12 年前

    您需要使用运算符Equals:

     var subCategories = this.Repository.Categories.Where(c => c.ParentId.Equals(categoryId))
            .ToList().Cast<ICategory>();
    

    等于 fot可为null的类型返回 如果:

    返回 错误的

    • 当前可为null的结构的HasValue属性为true,另一个参数为null。
    • 当前可为null的结构的HasValue属性为false,其他参数不为null。

    更多信息请点击这里 Nullable<.T>.Equals Method

        5
  •  1
  •   Ryan Versaw    15 年前

    public IEnumerable<ICategory> GetSubCategories(long? categoryId)
    {
        var subCategories = this.Repository.Categories.Where(c => (!categoryId.HasValue && c.ParentId == null) || c.ParentId == categoryId)
            .ToList().Cast<ICategory>();
    
        return subCategories;
    }
    
        6
  •  1
  •   Jiří Herník    11 年前

    或者你可以简单地使用这个。它还将转换为更好的sql查询

    Where((!categoryId.hasValue && !c.ParentId.HasValue) || c.ParentId == categoryId)
    
        7
  •  0
  •   Kevbo    8 年前

    Linq to Entities支持空值协同(?),因此只需将空值实时转换为默认值即可。

    Where(c => c.ParentId == categoryId ?? 0)