LINQ NullReferenceException on DefaultIfEmpty - linq

I'm looking for a solution to the problem of having the DefaultIfEmpty() extension method not picking up null values when used in a LINQ outer join.
Code as follows:
var SummaryLossesWithNets = (from g in SummaryLosses
join n in nets
on g.Year equals n.Year into grouping
from x in grouping.DefaultIfEmpty()
select new
{
Year = g.Year,
OEPGR = g.OccuranceLoss,
AEPGR = g.AggregateLoss,
OEPNET = ((x.OEPRecovery == null) ? 0 : x.OEPRecovery),
AEPNET = ((x.AEPRecovery == null) ? 0 : x.AEPRecovery),
});
In the List SummaryLosses there are many years worth of data I wish to join to the table 'nets' which contains a sub-portion of the years. The exception is thrown on x being a null value, I am assuming because the years in SummaryLosses not matched by years in nets creates null values in the grouping list.
How should one go about checking for the null value here? As you can see I've attempted to check for null on the properties of x, but since x is null this doesn't work.
Kind regards
Richard

Simply check whether x is null instead:
OEPNET = x == null ? 0 : x.OEPRecovery,
AEPNET = x == null ? 0 : x.AEPRecovery
Or if x.OEPRecovery and x.AEPRecovery are nullable properties too, use:
OEPNET = x == null ? 0 : (x.OEPRecovery ?? 0),
AEPNET = x == null ? 0 : (x.AEPRecovery ?? 0)

If you have many join statements
check check all joined tables and ensure that the foreign key you are using
(in comparing or lets say Interested in) is not null

Related

Unable to create a constant value of type 'System.DBNull'. Only primitive types or enumeration types are supported in this context

I try to apply left outer join on the basis of two ids one in the primary key of one table while the foreign key of another table also nullable
var yarnPOFilter_Grid = (from yrq in _context.Yarn_Requisition_Details
//join ypo in
_context.Yarn_PurchaseOrder_Details on yrq.YarnRequsitionDetailID
equals
ypo.YarnRequsitionDetailID into t
join ypo in
_context.Yarn_PurchaseOrder_Details on yrq.YarnRequsitionDetailID
equals
DBNull.Value.Equals(ypo.YarnRequsitionDetailID) ? 0 :
ypo.YarnRequsitionDetailID into t
from rt in t.DefaultIfEmpty() //
DefaultIfEmpty preserves left-hand elements that have no matches on the
right side
select new
{
YarnRequsitionDetailID =
(rt.YarnRequsitionDetailID == null ? long.MinValue :
rt.YarnRequsitionDetailID),
yrq.YarnID,
yrq.Yarn.YarnName,
yrq.YarnFellowID,
yrq.Yarn_FellowCodes.YarnFellowCode,
yrq.QuantityRequired,
rt.QuantityOrdered,
QuantityBalance_Custom =
yrq.QuantityRequired - rt.QuantityOrdered
}).ToList();
return yarnPOFilter_Grid;
I get this error message when I deal with null in joining condition
Unable to create a constant value of type 'System.DBNull'. Only primitive types or enumeration types are supported in this context.
Execute ToList() First before Select as there is no sql equivalent to the conditions you added in the YarnRequsitionDetailID = (rt.YarnRequsitionDetailID == null ? long.MinValue : rt.YarnRequsitionDetailID)
so it will be
from rt in t.DefaultIfEmpty()).ToList().Select(c => new
{
YarnRequsitionDetailID =
(c.rt.YarnRequsitionDetailID == null ? long.MinValue :
c.rt.YarnRequsitionDetailID),
c.yrq.YarnID,
c.yrq.Yarn.YarnName,
c.yrq.YarnFellowID,
c.yrq.Yarn_FellowCodes.YarnFellowCode,
c.yrq.QuantityRequired,
c.rt.QuantityOrdered,
QuantityBalance_Custom =
c.yrq.QuantityRequired - c.rt.QuantityOrdered
}).ToList();
i hope this solved your previous problem

LINQ query with Left Join, Group by without null List

I am working on LINQ query with Left-Join and groupBy, so I have list of questions which may or may not have answer collections. I want all the question group by question and their answer list, if it is null then don't want to add.
My current solution works fine but it still add a list with null where no answer is there hence giving me wrong result on Answer count()
var dhd = (from question in Context.Questions
join answer in Context.Answers on question.Id equals answer.QuestionId into ps
from answerDetail in ps.DefaultIfEmpty()
group answerDetail by question into grouped
select new
{
Question = grouped.Key,
Answer = grouped.ToList(),
//Answer = grouped.ToList() == null ? "(No Answer)" : grouped.Select(x => x.Value).FirstOrDefault(),
TotalAnswerCount = grouped.Count()
}).ToList();
I have tried following script in above code and it throw null exception
Answer = grouped.ToList() == null ? "(No Answer)" : grouped.Select(x => x.Value).FirstOrDefault(),
When you call ps.DefaultIfEmpty() it's making a list with null for non-matching element. If you want to get just null instead of a list with a null element, then try this code:
Answer = grouped.FirstOrDefault() == null ? null : grouped.ToList(),
If there's no match, then Answer is null, otherwise you get a list.
I think issue occur because of type so try this one:
Answer = grouped.ToList() == null ? null : grouped.Select(x => x.Value).FirstOrDefault(),

Dynamic CRM :Contains<> is not working in CRM

My code is as below:
var conntionRecord1Id = (from connectionBase in orgServiceContext.CreateQuery("connection")
where connectionBase["record1roleid"] == null
select new { OpportunityId = connectionBase["record1id"] }).Distinct().ToList();
var query =
from opportunity in orgServiceContext.CreateQuery("opportunity")
orderby opportunity["createdon"] ascending
select new
{
Topic = opportunity.Attributes.Contains("name") == true ? opportunity["name"] : null,
OpportunityId = opportunity.Attributes.Contains("opportunityid") == true ? opportunity["opportunityid"] : null,
PostalCode = opportunity.Attributes.Contains("new_address_postalcode") == true ? opportunity["new_address_postalcode"] : null,
};
var result = (from f in query.ToList() where conntionRecord1Id.Contains(f.OpportunityId) select f).ToList();
But in above query where i am using Contains it giving count 0. even though I have common records in the list
The Contains Linq extension method does not know how to compare complex objects.
Comparing f.OpportunityId to a list of Guids instead of a list of an anonymous type will work:
var conntionRecord1Id = (from connectionBase in orgServiceContext
.CreateQuery("connection")
where connectionBase["record1roleid"] == null
select connectionBase.GetAttributeValue<Guid?>("record1id"))
.Distinct()
.ToList();
Implement IEqualityComparer in a custom comparer class to compare complex objects: https://stackoverflow.com/a/6694563/1817350
Keep in mind that calling .ToList() brings down all the records into memory and will cause performance problems with large amounts of records.

Difficult sort order with Linq to SQL

I have a List of objects that I need sorted a particular way.
The relevant table fields are:
ID (int)
IsMandatory (bit)
ParentID (int nullable)
Code (varchar)
I need them sorted by IsMandatory=true first, then by Code, but anything with a ParentID must be sorted by Code but appear straight after the row with the same ID as ParentID (and these records will always have IsMandatory set to NULL).
Some sample data, and this is also in the order in which they should appear when ordered:
ID=1, IsMandatory=1, ParentID=NULL, Code="A"
ID=2, IsMandatory=NULL, ParentID=1, Code="A"
ID=3, IsMandatory=NULL, ParentID=1, Code="B"
ID=4, IsMandatory=1, ParentID=NULL, Code="B"
ID=5, IsMandatory=0, ParentID=NULL, Code="C"
ID=6, IsMandatory=NULL, ParentID=5, Code="A"
ID=7, IsMandatory=0, ParentID=NULL, Code="D"
How would this best be accomplished in a Linq to SQL orderby?
It was a difficult sort!
The reason for the difficulty stems from the fact you are ordering on the Parents record properties first and then the actual records properties.
I tried to make the variables as self explanatory as possible, but if you have any questions please ask!
var query = from x in context.Table
let parent = list.FirstOrDefault(y => x.ParentID == y.ID)
let parentIsMandatory = parent == null ? x.IsMandatory : parent.IsMandatory
let parentIsMandatoryOrder = parentIsMandatory == true ? 0 : 1
let parentCode = parent == null ? x.Code : parent.Code
let parentId = x.ParentID ?? x.ID
let isParent = x.ParentID == null ? 0 : 1
orderby parentIsMandatoryOrder, parentCode, parentId, isParent, x.Code
select x;

How to pass an external parameter to LINQ where clause in CRM

I have a LINQ query which works fine as for stand alone lists but fails for CRM
var lst = new List<bool?>();
lst.Add(null);
lst.Add(true);
lst.Add(false);
bool IsWet = false;
var newlst = from exch_HideVoiceSignature in lst where
(((exch_HideVoiceSignature!=null && exch_HideVoiceSignature==false
|| exch_HideVoiceSignature== null) )&& !IsWet) select exch_HideVoiceSignature;
newlst.Dump();
var question = from q in exch_questionSet where ((q.exch_HideVoiceSignature != null
&& q.exch_HideVoiceSignature.Value == 0 )|| q.exch_HideVoiceSignature == null )
&& !IsWet select q.exch_HideVoiceSignature;
question.FirstOrDefault().Dump();
As you can see I can pass the variable IsWet to LINQ query for a standard list fine and get values for first list. But when I execute the same for second list, I get the following error
Invalid 'where' condition. An entity member is invoking an invalid property or method
The CRM LINQ provider won't support the evaluation you attempting. It only supports evaluation of where criteria is evaluating an entity field.
That's not a problem. Since you want the LINQ query to only use the where clause if IsWet is false (correct me if I'm wrong on that.) So we simply do the evaluation to determine if the where clause should be added or not. Then execute your query.
var question = from q in exch_questionSet
select q.exch_HideVoiceSignature;
if (!IsWet)
{
question.Where(x => ((x.exch_HideVoiceSignature != null
&& x.exch_HideVoiceSignature.Value == 0) || x.exch_HideVoiceSignature == null));
}
question.FirstOrDefault().Dump();
I am constantly confronted with that problem.
Try to "detach" (for example call .ToArray()) your query (while it is "clear") from CRM and then filter query using external parameter. This should help.
var question =
(from q in exch_questionSet
where (
(q.exch_HideVoiceSignature != null && q.exch_HideVoiceSignature.Value == 0 ) ||
q.exch_HideVoiceSignature == null )
select q.exch_HideVoiceSignature
).ToArray().Where(q => !IsWet);
question.FirstOrDefault().Dump();
UPDATE
If you are using IsWet flag to control blocks of conditions (enable and disable them from the one point in the code) then probably you may be interested in class named PredicateBuilder which allows you to dynamically construct predicates.
Just because I had an existing query with lot of other joins etc. and I wanted to pass this additional parameter to it I ended up using a var statement which dumps the rows to a list and applies the where clause in the same statement
bool IsWet =true ;
var question = ...existing query ...
select new {
...existing output ...,
Wet =q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080001,
Voice = q.exch_HideVoiceSignature == null ||
(q.exch_HideVoiceSignature != null &&
q.exch_HideVoiceSignature.Value == 119080000) ,
}
;
var qq = IsWet ?
question.ToList().Where(X=> X.Wet ) :
question.ToList().Where(X=> X.Voice );
qq.FirstOrDefault().Dump();

Resources