43

NullableParentIdフィールドを持つCategoryエンティティがあります。以下のメソッドが実行中で、categoryIdがnullの場合、結果はnullのように見えますが、ParentId値がnullのカテゴリがあります。

ここの問題は何ですか、私は何が欠けていますか?

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

    return subCategories;
}

ちなみに、条件を(c.ParentId == null)に変更すると、結果は正常に見えます。

4

7 に答える 7

54

他の方法:

Where object.Equals(c.ParentId, categoryId)

また

Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)
于 2010-10-23T19:42:52.950 に答える
30

最初に行うことは、ログを記録して、生成された 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);
    }
于 2009-02-25T14:08:47.463 に答える
5

私の推測では、これは DBMS のかなり一般的な属性によるものであると考えられます。2 つのものが両方とも null であるからといって、それらが等しいというわけではありません。

少し詳しく説明するために、次の 2 つのクエリを実行してみてください。

SELECT * FROM TABLE WHERE field = NULL

SELECT * FROM TABLE WHERE field IS NULL

「IS NULL」構造の理由は、DBMS の世界では、NULL の意味は値が未定義であるため、NULL != NULL であるためです。NULL は未定義を意味するため、2 つの null 値が等しいとは言えません。定義上、それらが何であるかわからないからです。

"field == NULL" を明示的にチェックすると、LINQ はおそらくそれを "field IS NULL" に変換します。しかし、変数を使用する場合、LINQ は自動的にその変換を行わないと思います。

この問題の詳細については、MSDN フォーラムの投稿をご覧ください。

良い「チート」は、ラムダを次のように変更することです。

c => c.ParentId.Equals(categoryId)
于 2009-02-25T14:08:57.090 に答える
4

演算子 Equals を使用する必要があります。

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

次の場合、null 許容型と等しいとtrueが返されます。

  • HasValue プロパティは false で、他のパラメーターは null です。つまり、定義上、2 つの null 値は等しくなります。
  • HasValue プロパティは true であり、Value プロパティによって返される値は他のパラメーターと同じです。

次の場合はfalseを返します。

  • 現在の Nullable 構造体の HasValue プロパティは true で、他のパラメーターは null です。
  • 現在の Nullable 構造体の HasValue プロパティは false であり、他のパラメーターは null ではありません。
  • 現在の Nullable 構造体の HasValue プロパティは true であり、Value プロパティによって返される値は他のパラメーターと等しくありません。

詳細はこちらNullable<.T>.Equals メソッド

于 2012-06-14T13:42:41.667 に答える
1

このような単純なものはどうですか?

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;
}
于 2009-02-25T15:04:07.457 に答える
0

Linq to Entities は Null Coelescing (??) をサポートしているため、その場で null をデフォルト値に変換するだけです。

Where(c => c.ParentId == categoryId ?? 0)
于 2016-03-30T20:22:41.053 に答える