Linq check to see is there any NULLs in a set of DataRows? - linq

I have a set DataRows and I want to check if any of the fields in any of those rows has a NULL value in it. I came up with this below, but I'm not sure because I'm nesting an ALL.
result.AsEnumerable().AsQueryable().All(o => o.ItemArray.All(i=>i == DBNull.Value))
Hard to tell because I can't put a "watch" in lambdas.

Actually you need to use Any (in your code you will return true if All values are null) and AsQueryable() is useless in this case.
bool nullFound = result.AsEnumerable()
.Any(o => o.ItemArray.Any(i=>i == DBNull.Value || i == null));
Then, If you need a list of all rows with some value null, just do the following:
var rowsWithNulls = result.AsEnumerable()
.Where(o => o.ItemArray.Any(i=>i == DBNull.Value || i == null))
.ToList();
P.S.
I also added a null check to be more safe, but if you are sure to have only DBNull.Value, you can remove it.

Not sure if this is the correct answer. I'm also rather new to Linq, but i believe you can do something like this;
result.AsEnumerable().AsQueryable().SingleOrDefault(o => o.ItemArray.All(i=>i == DBNull.Value))
This will return an list of items or null if there aren't any. Not sure if you can also nest it, but don't see why it wouldn't be possible

Related

Entity Framework: Any or All - Unable to create a constant value of type 'System.Collections.Generic.List`1'

I am trying to do something like this:
from t in ent.myEntities
where SelectedProperties == null || SelectedProperties.Any(le => le == t.Entity)
select t
basically trying to cover 2 cases. accepting an empty list, should return all entities, or filter on the list if it is supplied.
above actually does work when i supply the list, however in the case when it is null i get:
Unable to create a constant value of type
'System.Collections.Generic.List`1'. Only primitive types ('such as
Int32, String, and Guid') are supported in this context
also tried using this with a string array:
where arr == null || arr.Contains(t.Entity)
is it possible to have such a condition without having to build a predicate (which is a bigger effort)?
You might want to try using the list in a simpler way:
where SelectedProperties == null || SelectedProperties.Contains(t.Entity)
It may well not work, but it's worth a try. Otherwise, if this is really your whole query, I'd just write it as:
var query = SelectedProperties == null
? ent.myEntities
: ent.myEntities.Where(t => SelectedProperties.Contains(t.Entity));
EDIT: Okay, if you have to use Any, and have lots of these to compose, you can do it like this:
var query = ent.myEntities;
if (SelectedProperties != null)
{
query = query.Where(t => SelectedProperties.Any(x => x == t.Entity));
}
if (SomethingElse)
{
query = query.Where(...);
}
// etc
I'm using EF5, something like this will fix the issue:
ent.myEntities.ToList().Where(t => SelectedProperties == null || SelectedProperties.Contains(t.Entity));

Reversing IQueryable based on passed property for sorting logic

I am implementing sort based on parameter passed to ascending or descending OrderBy method
else if (showGrid.Sortdir == "DESC")
{
alerts = DB.Incidents.OfType<Alert>().Where(
a =>
a.IncidentStatusID == (int)AlertStatusType.New ||
a.IncidentStatusID == (int)AlertStatusType.Assigned ||
a.IncidentStatusID == (int)AlertStatusType.Watching)
.OrderByDescending(a => showGrid.Sort);
}
else
{
alerts = DB.Incidents.OfType<Alert>().Where(
a =>
a.IncidentStatusID == (int)AlertStatusType.New ||
a.IncidentStatusID == (int)AlertStatusType.Assigned ||
a.IncidentStatusID == (int)AlertStatusType.Watching)
.OrderBy(a => showGrid.Sort);
}
In case of ascending order sorting it works fine but for descending order sorting doesn't work. I debugged the code and I found that list is not revered its same as ascending order. Please help me
Ok. I've written a small test. It is funny, but your code can actually compile and work, but very differently from what you expect :)
Obviously showGrid is not of type Alert, it is an instance of some other class, that incidentally have the same propery as Alert, called Sort.
First I was confused, because expected this code to fail to compile.
// The signature of OrderBy
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector)
// In your case it will result in
public static IOrderedQueryable<Alert> OrderBy<Alert, string>(this IQueryable<Alert> source, Expression<Func<Alert, string>> keySelector)
//when you call it like you do
DB.Incidents.OfType<Alert>().OrderByDescending(a => showGrid.Sort);
// You supply a property from object of type different from your entity.
// This is incorrect usage, the only object you can use here is the
// "a" argument. Like this:
DB.Incidents.OfType<Alert>().OrderByDescending(a => a.Sort);
// Because anything else does not make any sense to entity provider.
So your order by simply does not work.
As far as I understood, what you want is to perform sorting based on selection in UI. This is not easily achieved in strongly-typed LINQ. Because as I showed above, you send a property, not a value to the OrderBy. It does not care about the value inside the prop. So there are several solutions to the problem:
Write a big switch, that will check every possible Sort value, and will append appropriate 'OrderBy(a => a.YouPropToSort)' to the query. This is straitforward, and you should begin with this. Of course this is a static way, and will require to change code everytime you want new columns to be added for sorting.
Create argument for your OrderBy using 'LINQ Expression Trees'. For you case it should not be very hard to do. Look for the term, you will find a lot of examples.
Try to use Dynamic LINQ. I did not not use it myself, just looked at the docs. This seems to be an extension to the normal LINQ which allows you to write parts of queries as strings, to overcome limitations like the current one with dynamic sorting.
Here's my solution to sorting based on user selections:
Create your base query
var query = DB.Incidents.OfType<Alert>.Where(
a =>
a.IncidentStatusID == (int)AlertStatusType.New ||
a.IncidentStatusID == (int)AlertStatusType.Assigned ||
a.IncidentStatusID == (int)AlertStatusType.Watching);
and then apply your sort using a case statement
bool desc = showGrid.SortDir = "DESC";
switch(showGrid.Sort)
{
case "col1":
query = desc ? query.OrderByDescending( a => a.Col1 ) : query.OrderBy( a => a.Col1 );
break;
case "col2":
query = desc ? query.OrderByDescending( a => a.Col2 ) : query.OrderBy( a => a.Col2 );
break;
...
}
var results = query.ToList();

Filter a generic list based on a reflected value of its entries with linq

I have a generic list of objects from which I want to whittle down based on a reflected value within it
List<MyCaseObj> CasesInGroup = ....;
PropertyInfo piItem = typeof(MyCaseObj).GetProperty(SomePropertyName).PropertyType.GetProperty(SomeValueMemberName);
var CasesToProcess = (from csh in CasesInGroup
where ((Guid)piItem.GetValue(piField.GetValue(csh, null), null))
.In(fld.Items.Select(i => i.ItemID))
select csh);
however it transpires that the particular value may sometimes be null, and the In extension is not to fond of that throwing a 'Non-static method requires a target.' exception
adding a && (Guid)piItem.GetValue(piField.GetValue(csh, null), null) != null doesn't work, and does the reflection twice anyway which doesnt seem right in the first place even if it did..
could someone explain how to get around this, or maybe just a nicer way to do this in the first place.
any help, pointers or such would be gratefully recieved
thanks
You could replace
(Guid)piItem.GetValue(piField.GetValue(csh, null), null))
with
(csh != null ? (Guid)piItem.GetValue(piField.GetValue(csh, null), null)) : Guid.Empty)
which should work unless Items sometimes contains Guid.Empty.
P.S. If you are up for learning something very, very cool, convert this expression to a lambda:
var myCaseType = typeof(MyCaseObj);
var param = Expression.Parameter(myCaseType);
var cond = Expression.Condition(
Expression.NotEqual(param, Expression.Constant(null, myCaseType))
, Expression.Property(param, "SomePropertyName")
, Expression.Constant(Guid.Empty)
);
var lambda = (Func<MyCaseObj,Guid>)Expression.Lambda(cond, param).Compile();
You can now re-write your select like this:
var CasesToProcess = (from csh in CasesInGroup
where lambda(csh)In(fld.Items.Select(i => i.ItemID))
select csh);

If condition in LINQ Where clause

With Linq, can I use a conditional statement inside of a Where extension method?
var query = someList.Where(a => (someCondition)? a == "something" : true);
so, if 'someCondition' is false, 'Where' will be skipped.
Yes you can like:
var query = someList.Where(a => a == "something");
if (condition)
{
query = query.Where(b => b == "something else");
}
var result = query.ToList();
Because Where is producing an IQueryable, the execution is deferred until the ToList in my example so you can chain Wheres together as much as you want and then just execute it after you have passed all your conditions.
Make use of WhereIf extenstion method avaialbe in linq
Example
if (SearchControlMain.PostingID.HasValue)
query = query.Where(q => q.PostingID == SearchControlMain.PostingID);
instead of above go for the below
query = query.WhereIf(SearchControlMain.CategoryID.HasValue, q => q.CategoryID == SearchControlMain.CategoryID);
LINQ WhereIf Extension Method
LINQ to SQL Where Clause Optional Criteria
Not sure if this is appropriate but it is quite useful, you can use ifs quite handily with conditional where clauses:
var r = (from p in productinfo.tblproduct
where p.Accountid == accountid
select p);
if (uuf1 != null)
r = r.Where(p => p.UnitUserField1 == uuf1);
if (uuf2!= null)
r = r.Where(p => p.UnitUserField2 == uuf2);
So the where clause will be amended according to what is in UUF1 or UUF2 i.e. you might have only UUF1 with info, in which case it will take that and ignore the UUF2 where clause, you might have both in which it will take both or you might not have anything in UUF1 or 2 and your where clause will just take the accountid as the where clause.
In my case there were two "conditional" where depending on search keys, so I did:
var query = db.Package.Include("SomeThing")
.Where(item => searchString1 == null || searchString1 == "" || item.Contains(searchString1))
.Where(item => searchString2 == null || searchString2 == "" || item.Contains(searchString2));
...
from item in items
where condition1
&& (condition2 ? true : condition3)
select item
This is how can you can do it with the noob Linq syntax.
This applies the condition3 only if condition2 is false.
If condition2 is true, you are essentially doing && true which has no effect on the where clause.
So it is essentially doing this:
if(condition2)
{
from item in items
where condition1
select item
else
{
from item in items
where condition1
&& condition3
select item
}
I had a scenario like this where I had to check for null within the list itself. This is what I did.
items = from p in items
where p.property1 != null //Add other if conditions
select p;
// Use items the way you would use inside the if condition
But as Kelsey pointed out this would work too -
items = items.Where(a => a.property1 != null);
I'm not sure what the question is, but a possible answer could be:
Yes,
list.Where(item => { if (Foo(item)) return true; else return false; });
It would be a complicated way of saying something simple, though.
In my case, I wanted to keep the elements which met my criteria and log the ones that didn't without iterating multiple times.
var merchantsWithLocations = allMerchants.Where(m =>
{
if (m.Locations?.Any() != true)
{
_logger.Log("Merchant {merchantId} has no locations", m.Id);
return false;
}
return true;
};
Any time you want to do a side-effect per element (such as logging), breaking out the lambda into a statement body makes it easy to reason about.

LINQ Dynamic Expression API, predicate with DBNull.Value comparison

I have an issue using the Dynamic Expression API. I cannot seem to compare a DataTable field against DBNull.Value. The API is supposed to be able to "support static field or static property access. Any public field or property can be accessed.". However given the following query:
var whatever = table1.AsEnumerable()
.Join(table2.AsEnumerable(),
(x) => x.Field<int>("Table1_ID"),
(y) => y.Field<int>("Table2_ID"),
(x, y) => new { x, y})
.AsQueryable()
.Where("x[\"NullableIntColumnName\"] == DBNull.Value");
I end up getting the error: "No property or field 'DBNull' exists in type '<>f__AnonymousType0`2'"
Anyone have ideas on how to get around this? I can't use Submission.Field("NullableIntColumnName") in the string passed to the Where method either, btw, or else I would be able to compare against null instead of DBNull.Value.
Well, I finally got it. cptScarlet almost had it.
var values = new object[] { DBNull.Value };
...
.Where("x[\"NullableIntColumnName\"] == #0", values);
or
.Where("x[\"NullableIntColumnName\"] == #0", DBNull.Value);
What happens when you replace your current .Where with something like
.Where(string.format("x[\"NullableIntColumnName\"] == {0}",DBNull.Value));
If you change x.Field<int>("Table1_ID") to x.Field<int?>("Table1_ID") then you'll get nullable integers instead of regular integers, and any DBNull values will be converted to simple C# null values. Based simply on your code snippet, I'm not even sure you'd need dynamic expressions - a simple .Where(foo => foo.x == null) ought to work.
In general, you can also try:
.Where("NullableColumnName.HasValue");
Sorry to non-answer with a USL but...
Have you looked in the source? There's not a lot of it. My guess is that DBNull is not in the list of registered root objects.
I dont have the source to hand right now, but it is also likely to tell you what any other constants one might compare against might be.
.Where(a => a.IntColName == null);
Edit:
Sorry, I did't see this dynamic requirement... Dynamic would be: (at least in Framework 4)
var intColName = "...";
.Where(string.Format("it.{0} is null", intColName));

Resources