C# EF DefaultIfEmpty with Where().Select() - c#

Is there a way similar to what we can do with linq for left outer join with method based query syntax.
e.g.
var a = from m in context.MainClass
join r in context.RefClass on m.RefID equals r.ID into joinedent
from j in joinedent.DefaultIfEmpty()
select new { m.Name , j.TypeName }
Can I convert this into method based syntax with navigation property default if null
var a = context.MainClass.Select(x=> new {
m.Name
m.RefClass.TypeName // here need default if RefClass is null
})
I can do like (m.RefClass != null)?m.RefClass.TypeName:"" but would like to know if there is a proper way to do this like in above linq.
Thanks

Just use new initialization in DefaultIfEmpty parameter
var a = from m in context.MainClass
join r in context.RefClass on m.RefID equals r.ID on joinedent
from j in joinedent.DefaultIfEmpt(new RefClass())
select new { m.Name , j.TypeName }
Hope the problem will be solve

When EF executes the Linq against the database, the m.RefClass.TypeName would return #null, where the same statement against objects would throw a NullReferenceException.
m.RefClass?.TypeName should return string.Empty in both cases.
Update: As mentioned the ?. is not allowed in expression trees, however the following does work:
var a = context.MainClass.Select(x=> new {
m.Name
TypeName = m.RefClass.TypeName ?? ""
})
EF expressions will return #null for properties where the child reference is null rather than a null reference exception. However checking the RefClass for null would be safer in case the expression gets copied/moved in a way where it would be run against objects rather than through EF.
On a curious side note I did come across an interesting side-effect while testing this: This only works properly if the relationship between parent and child is mapped as optional. (Obviously) In my case I had an existing test relationship that was set up as "Required" or non-nullable. I'd changed the schema to make the child ID null-able and it did not throw any exceptions, it simply returned no rows

Can you try using Include?
var a = context.MainClass.Include("RefClass")
.Select(x => new {
m.Name
m.RefClass.TypeName // here need default if RefClass is null
})

Related

What is the equivalent LINQ to SQL query expression of this SQL statement?

SQL query run OK:
select o.OpName,isnull(Amount,0) from Setup_tblOperator o
left join
(
select t.opid,sum(isnull(t.Amount,0)) Amount from
Load_tblTransaction t
where cast(t.RequestTime as date)='2017-04-24'
group by t.opid
) t on t.OpId=o.OpId
where o.IsActive=1
I tried following code in LINQ to SQL:
var trans = (from o in mouDataEntities.Setup_tblOperator
join t in mouDataEntities.Load_tblTransaction
on o.OpId equals t.OpId into ot
from n in ot.Where(
t => DbFunctions.TruncateTime(t.RequestTime) ==
DbFunctions.TruncateTime(seldate))
.DefaultIfEmpty()
select new
{
Operator = o.OpName,
Amount= n.Amount
});
var gt = trans.GroupBy(t => t.Operator)
.Select(n => new { Operator = n.Key, Amount = n.Sum(a=>a.Amount) })
.ToList();
It throws an error:
The cast to value type 'System.Int32' failed because the materialized
value is null. Either the result type's generic parameter or the query
must use a nullable type.
There are a few cases where the straightforward SQL to C# translation gets accepted, but fails at run-time. In C#, set.DefaultIfEmpty().Select(n => n.Amount), where n.Amount has type int, would have a result type IEnumerable<int>. It would fail with a NullReferenceException if set were empty, because in that case n would become null as well. Therefore, there is no reason why you'd need int?, since you can't ever get null as a result.
In SQL, it's not so easy. Retrieving a column of the default row introduced by LEFT JOIN is valid, and produces NULL.
But the C# code is expecting a value of type int, and an int can't be null.
You need to find some way to trick the type system so that you can specify how null should be handled. A simple cast suffices:
Change
Amount = n.Amount
to
Amount = (int?) n.Amount
Or, to turn null into 0,
Amount = (int?) n.Amount ?? 0

Avoid NullReferenceException in LINQ Expression on Datatable column

I am stuck with null values in my Datatable "articles". Using LINQ to get a list of articles works for column ArticleId but with column "ArticleVariations" the null values are killing me.
var result = this.articles.AsEnumerable().Where(r =>r.Field<String>("ArticleId").Equals(artNo)); // works. no nulls there ;)
var result = this.articles.AsEnumerable().Where(r =>r.Field<String>("ArticleVariations").Equals(artNo)); // stuck with nulls here
If the column contains nulls, I get an NullReferenceException, Can I avoid this somehow and is it possible to merge both expressions?
You can use null-conditional and null-coalescing operators:
var result = this.articles.AsEnumerable()
.Where(r =>r.Field<String>("ArticleVariations")?.Equals(artNo) ?? false);
The problem obviously occurs because r.Field<String>("ArticleVariations") retuns null. Thus you have to check for null before calling Equals on it.
For that you can call multiple statements within a LINQ-expression:
var result = this.articles.AsEnumerable().Where(r => {
var res = r.Field<String>("ArticleVariations");
if (res != null) return res.Equals(artNo);
else return false;
});
If the field can be null then just reverse your test:
var result = this.articles.AsEnumerable().Where(r => artNo.Equals(r.Field<String>("ArticleVariations")));
Then all you need to do is check that artNo is not null before making the call:
List<Type> result;
if (string.IsNullOrWhiteSpace(artNo))
{
result = new List<Type>();
}
else
{
result = this.articles.... as before
}
Where just takes a function which returns a bool to determine if it should filter an item out of a collection. You can write it with a multi-statement body just like any other function to make nulls easier to deal with. Something like this should be a good starting point:
.Where(r => {
string articleVariations = r.Field<string>("ArticleVariations");
return articleVariations != null && articleVariations.Equals(artNo);
});
IF you want to combine those checks somehow to build a list where one or the other of the given fields matches your artNo, you can just add it to the function body.
If the column contains nulls, I get an NullReferenceException, Can I avoid this somehow
Avoid using instance Equals methods where possible. Use the respective operators or static Equals methods because they handle correctly nulls for you.
In your concrete case, the easiest way is to replace Equals with ==:
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleId") == artNo);
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleVariations") == artNo);
and is it possible to merge both expressions?
It depends on what do you mean by "merging" them. If you mean matching article or variation by the passed artNo, then you can use something like this
var result = this.articles.AsEnumerable()
.Where(r => r.Field<string>("ArticleId") == artNo
|| r => r.Field<string>("ArticleVariations") == artNo);

LINQ C# Join with Left-Join result

I'm trying to do a left-join with the result of another left-join but in some cases it returns me null reference error (obviously), is there any way to do this without using foreach after select?
var result = from f in foo
from ex in exp.Where(w => w.id == f.idFoo).DefaultIfEmpty()
from te in tes.Where(w => w.id == ex.anyID).DefaultIfEmpty()
select new
{
var1 = f.something,
...
var2 = te.anything
};
That's happening because DefaultIfEmpty is returning a sequence with a single null element. Then you are trying to access properties on a null element.
Use the overload of DefaultIfEmpty to return a non-null default value (of the appropriate data type):
var result = from f in foo
from ex in exp.Where(w => w.id == f.idFoo)
.DefaultIfEmpty(new Exp())
from te in tes.Where(w => w.id == ex.anyID)
.DefaultIfEmpty(new Tes())
select new
{
var1 = f.something,
...
var2 = te.anything
};
That way you won't be trying to access properties on null elements.
Edit based on comments. In the query, one place that null elements arise is when a Where results in zero matches. For instance, in the third from the ex variable might be a sequence of one null element, and again in the select the te might also be such a sequence. In both cases, accessing a property will throw an exception.
Alternatively, you could do a null test every time you are going to access a property. That would become verbose fast.
Something like this:
var2 = te != null ? te.anything : null

object reference error in LINQ query

var query1 = from a in inputDataRecords
from b in employeeDataRecords
.Where(badgeNumber => a.Responsi == badgeNumber.Badge)
.Where(badgeNumber => a.Auth == badgeNumber.Badge)
.Where(badgeNumber => a.ByN == badgeNumber.Badge)
.DefaultIfEmpty()
select new {a,
responsibleName = b.EmployeeName,
authName = b.EmployeeName,
createName = b.EmployeeName};
gives me an error of: Object reference not set to an instance of an object.
I know it's because I'm not referencing b.
But changing the select to:
select new {a, b,
responsibleName = b.EmployeeName,
authName = b.EmployeeName,
createName = b.EmployeeName};
doesn't help. QuickWatch on query1 shows that b is null.
b is null beacuse you specifically called out in your query that b should be null if the sequence is empty through your use of DefaultIfEmpty. If you don't want to have a null b item when that sequence is empty, omit that operation. If you do, then you need to support having a null b value in your query.
note that you're using a number of items from .Where clauses, which could be null in the collection and thus throw this exception from any one of those lambdas. Try using a .Where(o => o != null) on both of those collections, and that may clear up the error.

Where Predicates in LINQ

How can I specify conditions in Where predicates in LINQ without getting null reference exceptions. For instance, if q is an IQueryable how can I do like:
Expression<Func<ProductEntity,bool>> predicate = p => !search.CategoryId.HasValue || (search.CategoryId.HasValue && search.CategoryId == p.CategoryId);
var q2 = q.Where(predicate);
Here search is an object that holds possible search conditions that may or may not be set like search.CategoryId might not be set but if it is I want to get the products that are set by that condition.
When I do this I get null reference exceptions.
You can use the null-coalescing operator ?? to replace a possible null value with a default value. The following sets tries to match the search.Category if it exists or simply creates an "always true" expression. This will be optimized by any good Linq query provider (e.g. LinqToSql).
Expression<Func<ProductEntity,bool>> predicate = p => (search.CategoryId ?? p.CategoryId) == p.CategoryId);
var q2 = q.Where(predicate);
Another possibility would be to dynamically compose a query predicate using PredicateBuilder. That's the way I do it for searches with a similar pattern as you use:
var predicate = PredicateBuilder.True<Order>();
if (search.OrderId))
{
predicate = predicate.And(a => SqlMethods.Like(a.OrderID, search.OderID);
}
// ...
var results = q.Where(predicate);
Let's dissect the line:
Expression<Func<ProductEntity,bool> predicate = p => !search.CategoryId.HasValue
|| (search.CategoryId.HasValue && search.CategoryId == p.CategoryId)
var q2 = q.Where(predicate);
So how many ways can we get null problems?
search (your "captured" variable) could be null
p could be null, meaning there is a null in the list
you've handled the case of search.CategoryId being null (Nullable<T>)
but maybe p.CategoryId (the category on a record in the list) is null (Nullable<T>) - however, I'm not sure that this would cause a NullReferenceException
q (the list / source) could be null
So: out of 5 options you've eliminated 1; look at the other 4? There is also the definite possibility that the issue is caused by something invisible not shown in the code; for example the get could be:
public int? CategoryId {
get {return innerObject.CategoryId;}
}
and innerObject could be null; if you eliminate the other 4 (pretty easy to do), look at at this one as a last resort.

Categories

Resources