Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compare nullable types in Linq to Sql

I have a Category entity which has a Nullable ParentId field. When the method below is executing and the categoryId is null, the result seems null however there are categories which has null ParentId value.

What is the problem in here, what am I missing?

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

By the way, when I change the condition to (c.ParentId == null), result seems normal.

like image 491
Ali Ersöz Avatar asked Feb 25 '09 14:02

Ali Ersöz


People also ask

Is null in LINQ to SQL?

In SQL Server, a SQL statement like 'NULL=NULL' evaluates to false. however 'NULL IS NULL' evaluates to true. So, for NULL values in your database columns, you need to use the 'IS' operator instead of the regular '=' operator.

How can you check a nullable variable for any type of value in C#?

You cannot directly access the value of the Nullable type. You have to use GetValueOrDefault() method to get an original assigned value if it is not null. You will get the default value if it is null.

Is null in EF core?

Data Annotations - Required Attribute in EF 6 & EF CoreEF will create a NOT NULL column in a database table for a property on which the Required attribute is applied.

What is variable nullable?

You typically use a nullable value type when you need to represent the undefined value of an underlying value type. For example, a Boolean, or bool , variable can only be either true or false . However, in some applications a variable value can be undefined or missing.


2 Answers

Other way:

Where object.Equals(c.ParentId, categoryId) 

or

Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId) 
like image 59
ariel Avatar answered Sep 20 '22 17:09

ariel


The first thing to do is to put on logging, to see what TSQL was generated; for example:

ctx.Log = Console.Out; 

LINQ-to-SQL seems to treat nulls a little inconsistently (depending on literal vs value):

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(); } 

So all I can suggest is use the top form with nulls!

i.e.

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>(); 

Update - I got it working "properly" using a custom 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);     } 
like image 23
Marc Gravell Avatar answered Sep 20 '22 17:09

Marc Gravell