nullable int in linq query [duplicate] - asp.net

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.

Other way:
Where object.Equals(c.ParentId, categoryId)
or
Where (categoryId == null ? c.ParentId == null : c.ParentId == categoryId)

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

My guess is that it's due to a rather common attribute of DBMS's - Just because two things are both null does not mean they are equal.
To elaborate a bit, try executing these two queries:
SELECT * FROM TABLE WHERE field = NULL
SELECT * FROM TABLE WHERE field IS NULL
The reason for the "IS NULL" construct is that in the DBMS world, NULL != NULL since the meaning of NULL is that the value is undefined. Since NULL means undefined, you can't say that two null values are equal, since by definition you don't know what they are.
When you explicitly check for "field == NULL", LINQ probably converts that to "field IS NULL". But when you use a variable, I'm guessing that LINQ doesn't automatically do that conversion.
Here's an MSDN forum post with more info about this issue.
Looks like a good "cheat" is to change your lambda to look like this:
c => c.ParentId.Equals(categoryId)

You need to use operator Equals:
var subCategories = this.Repository.Categories.Where(c => c.ParentId.Equals(categoryId))
.ToList().Cast<ICategory>();
Equals fot nullable types returns true if:
The HasValue property is false, and the other parameter is null. That is, two null values are equal by definition.
The HasValue property is true, and the value returned by the Value property is equal to the other parameter.
and returns false if:
The HasValue property for the current Nullable structure is true, and the other parameter is null.
The HasValue property for the current Nullable structure is false, and the other parameter is not null.
The HasValue property for the current Nullable structure is true, and the value returned by the Value property is not equal to the other parameter.
More info here Nullable<.T>.Equals Method

Or you can simply use this. It will also translate to a nicer sql query
Where((!categoryId.hasValue && !c.ParentId.HasValue) || c.ParentId == categoryId)

What about something simpler like this?
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;
}

Linq to Entities supports Null Coelescing (??) so just convert the null on the fly to a default value.
Where(c => c.ParentId == categoryId ?? 0)

Related

JSON Lists not removing duplicates with Distinct command

Currently I am querying a web service that returns a JSON string.
url = #"redacted url;
returnValue = new WebClient().DownloadString(url);
I am putting the return results into a list of items defined in a model class. I am then running a second JSON call searching a different field with that same search term.
url2 = #"redacted url2;
returnValue2 = new WebClient().DownloadString(url2);
I then create my lists and combine the lists using AddRange.
List<Order> shipments = JsonConvert.DeserializeObject<List<Order>>(returnValue);
List<Order> shipments2 = JsonConvert.DeserializeObject<List<Order>>(returnValue2);
shipments.AddRange(shipments2);
As a result there are some duplicates. To try and only return unique records I am using the command Distinct when sending to my MVC view from the controller.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct().ToList());
But for some reason it's still returning duplicates.
Any ideas on what I am doing wrong here?
Thanks in advance for any help!
I ended up correcting it using Shyju's comment above.
I changed the Distinct to the following.
return View(shipments.OrderBy(x => x.dtDateReceived).Distinct(new OrderComparer()).ToList());
Then built the following compare functions
// Custom comparer for the Order class
class OrderComparer : IEqualityComparer<Order>
{
// Orders are equal if their names and order numbers are equal.
public bool Equals(Order x, Order y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the order's properties are equal.
return x.sWorkOrderNumber == y.sWorkOrderNumber && x.sCustomerOrderName == y.sCustomerOrderName;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
public int GetHashCode(Order order)
{
//Check whether the object is null
if (Object.ReferenceEquals(order, null)) return 0;
//Get hash code for the sCustomerOrderName field if it is not null.
int hashOrderName = order.sCustomerOrderName == null ? 0 : order.sCustomerOrderName.GetHashCode();
//Get hash code for the sWorkOrderNumber field.
int hashOrderCode = order.sWorkOrderNumber.GetHashCode();
//Calculate the hash code for the order.
return hashOrderName ^ hashOrderCode;
}
}

default values in LINQ query

I have following Linq query/function in my MVC3 application.
public AuditTrail GetNamesAddressesEmployers(long registryId , int changedField) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress;
}
I want that if otherNameAndAddress = null then its properties should be assigned some values.
otherNameAndAddress has Name and description property. This GetNamesAddressesEmployers is being used at 3 places. I want to assign different values to name and description when otherNameAndAddress = null at all three locations.
You're already using FirstOrDefault() so why not specify the Default:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField)
{
return context.AuditTrails
.Where(a => a.ChangedField == changedField
&& a.RegistryId == registryId)
.DefaultIfEmpty(new AuditTrail { /* fill properties here */ })
.FirstOrDefault();
}
Well, you could change the return statement to:
return otherNameAndAddress ?? new AuditTrail { Name = "Default",
Description = "Default };
or something like that... but you say you want to assign different default values for different calls. That means you'll either need to pass the default in, or perform the defaulting (e.g. in the same way, via the null-coalescing operator) at the call site.
For example:
public AuditTrail GetNamesAddressesEmployers(long registryId, int changedField,
AuditField defaultValue) {
var otherNameAndAddress = (from a in context.AuditTrails
where a.ChangedField == changedField
&& a.RegistryId == registryId
select a).FirstOrDefault();
return otherNameAndAddress && defaultValue;
}
or keep it as it currently is, and use this at the call site:
var auditTrail = GetNamesAddressesEmployers(registryId, changedField) ??
new AuditTrail { Name = "Foo", Description = "Bar" };
It's not really clear which is best based on your description.
EDIT: As mentioned by Justin, you could use DefaultIfEmpty instead (just before FirstOrDefault). That means you have to pass the value in rather than doing it at the call site, but other than that they're very similar solutions.

Check if a key is available in Flex

I have a dictionary with objects as keys. How can I check if specific object is available in the dictionary?
hasOwnProperty won't work if the key is an object rather than a string.
checking that the value is null won't work if the key is in the dictionary, but with a null value.
The 'in' operator seems to work all the time.
var d:Dictionary = new Dictionary();
var a:Object = new Object();
d[a] = 'foo';
var b:Object = new Object();
d[b] = null;
var c:Object = new Object();
trace(a in d);
trace(b in d);
trace(c in d);
Returns
true
true
false
I believe this is a 'more correct' answer than the one posted above.
var b:Dictionary = new Dictionary();
if(b[key] != null) {
}
You can use array syntax and see if the value is null,
assertTrue(myDict["key"] == null)
If nulls are allowed values, use the hasOwnProperty method.
assertTrue(myDict.hasOwnProperty("key")==true)
Adobe, why don't you have a keyExists() function?
The most proper way is to compare the returned value with undefined:
if (dict["key"] !== undefined)
{
// do code when value does exist
}
as a key with a null associated value could exist in a dictionary.
Here is a good article that explains the topic.
You can use in to check for existing keys:
if ('key' in dict)
{
// do something
}
It works with object keys as well:
if (obj in dict)
{
// do something
}
Note that "obj" must be an existing object (defined or not) or it won't compile.

Collection of Property=>Value?

I would like to create a collection of key, value pairs in C# where the key is a property of an ASP.net control (e.g. ID) and the value is the value of that property. I would like to do this so I may later iterate through the collection and see if a given control has the properties in my collection (and the values of the properties in the control match the values defined in my collection). Any suggestions as to the best way to do this? Thanks for any help.
Pseudo-code example:
Properties[] = new Properties[] {new Property(){name="ID",value="TestControl1"}, new Property(){name = "Text",value="Type text here"}}
private bool controlContainsProperties(Control control){
foreach(Property Property in Properties[])
{
if((control does not contain property) || (control property value != Property.Value))
return false;
}
return true;
}
didn't test this, but here's my go:
public bool HasProperty( object target, IDictionary<string, object> values )
{
var targetType = target.GetType();
return values.All( kvp =>
{
var property = targetType.GetProperty( kvp.Key );
if ( property != null )
{
var value = property.GetValue( target, null );
if ( value != null )
return value.Equals( kvp.Value );
}
return false;
} );
}
My first idea was in using 'tag' property, but then I realized that there are no tags in APS.NET controls. However, there is an answered question about tags.
In the same thread there is a solution with 'Attributes' property map - looks promising.

The best way to build Dynamic LINQ query

Hi I am looking for best method for writing Dynamic LINQ query.
I have a function like
public IQueryable<Student> FindByAllStudents(int? id, string Name, int? CourseID, bool? IsActive) // like this way, all field values are passed
{
// code for compairision
return db.Student;
}
we can also write db.Students.where(predicate)
or
a query like
var students = from s in db.students where s.Name.Contains(Name)
s.ID.Equals(id)
//and so on....
So will this method works if i don't pass ID (i.e. Null)?
is proper way for all the datatypes?
The point is function can have all null values as a parameter for equivalence of select * from statement.
can any one help me to build best query with sample code?
Okay, it's not entirely clear what you want, but if you're trying to only add where clauses for the parameters which are non-null, you could do:
public IQueryable<Student> FindByAllStudents
(int? id, string name, int? courseID, bool? isActive)
{
IQueryable<Student> query = db.Student;
if (id != null)
{
query = query.Where(student => student.ID == id.Value);
}
if (name != null)
{
query = query.Where(student => student.Name.Contains(name));
}
if (courseID != null)
{
query = query.Where(student => student.CourseID == courseID.Value);
}
if (isActive != null)
{
query = query.Where(student => student.IsActive == isActive.Value);
}
return query;
}
I haven't tried that, and it's possible that LINQ to SQL would get confused by the code to find the value of the nullable value types. You may need to write code like this:
if (courseID != null)
{
int queryCourseID = courseID.Value;
query = query.Where(student => student.CourseID == queryCourseID);
}
It's worth trying the simpler form first though :)
Of course, all this gets a bit irritating. A helpful extension method could make life more concise:
public static IQueryable<TSource> OptionalWhere<TSource, TParameter>
(IQueryable<TSource> source,
TParameter? parameter,
Func<TParameter, Expression<Func<TSource,bool>>> whereClause)
where TParameter : struct
{
IQueryable<TSource> ret = source;
if (parameter != null)
{
ret = ret.Where(whereClause(parameter.Value));
}
return ret;
}
You'd then use it like this:
public IQueryable<Student> FindByAllStudents
(int? id, string name, int? courseID, bool? isActive)
{
IQueryable<Student> query = db.Student
.OptionalWhere(id, x => (student => student.ID == x))
.OptionalWhere(courseID, x => (student => student.CourseID == x))
.OptionalWhere(isActive, x => (student => student.IsActive == x));
if (name != null)
{
query = query.Where(student => student.Name.Contains(name));
}
return query;
}
Using a higher order function like this could get confusing if you're not really comfortable with it though, so if you're not doing very many queries like this you might want to stick with the longer but simpler code.

Resources