How to check null while joining multiple tables by LINQ? - c#

var Data = (from s in _context.PRD_RecipeItem.AsEnumerable()
where s.RecipeID == _RecipeID
from i in _context.Sys_ChemicalItem.Where(x => x.ItemID == s.ItemID).DefaultIfEmpty()
from u in _context.Sys_Unit.Where(x => x.UnitID == s.UnitID).DefaultIfEmpty()
from st in FinalStock.AsEnumerable().Where(x => x.ItemID == s.ItemID).DefaultIfEmpty()
from sup in _context.Sys_Supplier.Where(x => x.SupplierID == (st==null? 0: st.SupplierID)).DefaultIfEmpty()
select new PRDChemProdReqItem
{
ItemID = s.ItemID,
ItemName = (i == null ? null : i.ItemName),
RequiredQty = s.RequiredQty,
RequiredUnit = s.UnitID,
RequiredUnitName = (u == null ? null : u.UnitName),
RequsitionQty = s.RequiredQty,
ApproveQty = s.RequiredQty,
ApproveUnit = s.UnitID,
ApproveUnitName = (u == null ? null : u.UnitName),
PackSizeName = "",
PackQty = 0,
SizeUnitName = "",
RequisitionUnit = s.UnitID,
RequisitionUnitName = (u == null ? null : u.UnitName),
StockQty = (st == null ? null : (Math.Round(Convert.ToDecimal(st.ClosingQty), 2)).ToString()),
SupplierID = (st == null ? 0 : st.SupplierID),
SupplierName = (sup == null ? null : sup.SupplierName),
ItemSource = "Via Requisition"
}).ToList();
This is my code. When st is null, then I'm getting An exception of type System.Reflection.TargetException. How to solve this issue. Thanks in Advance.

Why don't you use join? This will take care of your null values.
See more details including source code here: http://msdn.microsoft.com/en-us/library/bb311040.aspx

Related

Prevent Entity Framework query from being evaluated locally

I have this query that is being partially evaluated locally and I am wondering how to prevent it.
It seems to be the conditional select that is causing the problem.
var fetchQuery = (
from udg in _entities.UberDirectGroups.AsNoTracking()
join uber in _entities.Ubers.AsNoTracking()
on udg.Id equals uber.Id
let memberCount = (
from t in _entities.UberDirects.AsNoTracking()
join u in _entities.Ubers.AsNoTracking()
on t.UberToId equals u.Id
where t.UberFromId == udg.Id && !u.Deleted
select u.UberTypeId == (byte)UberType.User ? 1 :
u.UberTypeId == (byte)UberType.Department ? u.Department.Users.Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.Office ? u.tblOffice.tblDepartment.SelectMany(d => d.Users).Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.ProjectGroup ? u.Group.GroupMembers.Select(pm => pm.User).Where(user => user.Deleted == false).Count() :
u.UberTypeId == (byte)UberType.Role ? _entities.Roles.Where(r => r.RoleDataId == u.tblRoleData.Id).Select(r => r.tblUser).Where(user => user.Deleted == false).Count() : 0
).Sum()
where
udg != null &&
uber != null &&
uber.InstanceId == instanceId &&
(!isSearch || udg.Name.Contains(searchText))
select new TargetGroupProjection
{
id = udg.Id,
name = udg.Name,
created = uber.Date,
toCount = memberCount
}
);

EF Core Linq join on multiple columns throws NullReference Exception

I have a rather ugly query that just had to be expanded by one more join. The query builds then throws a NullReferenceException runtime. As I'm struggling around the exception details I found the message at TargetSite/CustomAttributes/Message = "The method or operation is not implemented." But I don't know which method?
MarkedItems is the new join and I think the problem could be the join on multiple columns or that I had to add the new table into the group by clause. The same query runs in LinqPad with EF6, so this must be something that hasn't been implemented in EF7 yet.
EF Core version is 1.1.2.
The query:
var inventory = (from it in _ctx.Items
join i in _ctx.Inventories on it.Id equals i.ItemId into iit
from i in iit.DefaultIfEmpty()
join m in _ctx.MarkedItems on
new {
eancode = i.EANCode,
projectid = i.ProjectId
}
equals new {
eancode = (m != null ? m.EANCode : string.Empty),
projectid = (m != null ? m.ProjectId : Guid.Empty)
} into im
from m in im.DefaultIfEmpty()
where it.ProjectId == cmp.ProjectId
group i by new {
EANCode = it.EANCode,
ItemNo = it.ItemNo,
Name = it.Name,
BaseQty = it.BaseQty,
Price = it.Price,
m = (m != null ? m.EANCode : null)
} into lg
select new ComparisonBaseModel() {
EANCode = lg.Key.EANCode,
ItemName = lg.Key.Name,
Price = lg.Key.Price,
ScanQty = lg.Sum(s => s != null ? s.ScanQty : 0),
BaseQty = lg.Key.BaseQty,
DiffQty = lg.Sum(s => s != null ? s.ScanQty : 0) - lg.Key.BaseQty,
DiffPrice = lg.Key.Price * (lg.Sum(s=> s!= null ? s.ScanQty : 0) - lg.Key.BaseQty),
AllTasked = !lg.Any(s=>(s != null && s.InventoryTaskId == null) || s==null),
Flagged = lg.Key.m != null
}).Where(x=>x.DiffQty != 0);
Thanks to the comments I was able to find out the real problem with my query. I hadn't realized before, that Inventories (i) could be null, too, so I had to check for nulls even the i-s (not only m-s) in MarketItems join.
Not sure if this could be helpful to anyone but the error message was misleading after I have already run into some EF7/EF6 differences.
var inventory = (from it in _ctx.Items
join i in _ctx.Inventories on it.Id equals i.ItemId into iit
from i in iit.DefaultIfEmpty()
join m in _ctx.MarkedItems on
new {
eancode = (i != null ? i.EANCode : string.Empty),
projectid = (i != null ? i.ProjectId : Guid.Empty)
}
equals new {
eancode = (m != null ? m.EANCode : string.Empty),
projectid = (m != null ? m.ProjectId : Guid.Empty)
} into im
from m in im.DefaultIfEmpty()
where it.ProjectId == cmp.ProjectId
group i by new {
EANCode = it.EANCode,
ItemNo = it.ItemNo,
Name = it.Name,
BaseQty = it.BaseQty,
Price = it.Price,
m = (m != null ? m.EANCode : null)
} into lg
select new ComparisonBaseModel() {
EANCode = lg.Key.EANCode,
ItemName = lg.Key.Name,
Price = lg.Key.Price,
ScanQty = lg.Sum(s => s != null ? s.ScanQty : 0),
BaseQty = lg.Key.BaseQty,
DiffQty = lg.Sum(s => s != null ? s.ScanQty : 0) - lg.Key.BaseQty,
DiffPrice = lg.Key.Price * (lg.Sum(s=> s!= null ? s.ScanQty : 0) - lg.Key.BaseQty),
AllTasked = !lg.Any(s=>(s != null && s.InventoryTaskId == null) || s==null),
Flagged = lg.Key.m != null
}).Where(x=>x.DiffQty != 0);

SQL to Linq with aggregate function

I'm trying to do this in LINQ.
Can you guys help me to do this?
There some tool to help me with this conversion?
SELECT
CODIGO_DEPENDENCIA,
SUM(COALESCE(LOCAL_MOVEL, 0)) AS LOCAL_MOVEL,
SUM(COALESCE(LOCAL_FIXO, 0)) AS LOCAL_FIXO,
SUM(COALESCE(DDD_MOVEL, 0)) AS DDD_MOVEL,
SUM(COALESCE(DDD_FIXO, 0)) AS DDD_FIXO,
SUM(COALESCE(EXTERNA_INTERNACIONAL, 0)) AS EXTERNA_INTERNACIONAL
FROM (
SELECT
CODIGO_DEPENDENCIA,
CASE WHEN TIPO = 'SELM' THEN SUM(VALOR) END AS LOCAL_MOVEL,
CASE WHEN TIPO = 'SELF' THEN SUM(VALOR) END AS LOCAL_FIXO,
CASE WHEN TIPO = 'SENM' THEN SUM(VALOR) END AS DDD_MOVEL,
CASE WHEN TIPO = 'SENF' THEN SUM(VALOR) END AS DDD_FIXO,
CASE WHEN TIPO = 'SEI' THEN SUM(VALOR) END AS EXTERNA_INTERNACIONAL
FROM CAD_BILHETES
WHERE ID_PRODUTO IS NULL
AND ID_COMPETENCIA = 60
AND CODIGO_DEPENDENCIA IN (14, 160)
AND TIPO IN ('SEI', 'SELM', 'SENF', 'SELF', 'SENM')
AND VALOR <> 0
GROUP BY TIPO,CODIGO_DEPENDENCIA
) TAB
GROUP BY CODIGO_DEPENDENCIA
Obviously untested. Also, uncertain if null tests are needed or how they will react through SQL translation. It may be preferable to change the first query to return 0 when not matching and then just sum the results, but I wasn't sure the datatype of the columns.
var tab = from cb in CAD_BILHETES
where cb.ID_PRODUTO == null && cb.ID_COMPETENCIA == 60 && (new[] { 14, 160 }).Contains(cb.CODIGO_DEPENDENCIA) &&
(new[] { "SEI", "SELM", "SENF", "SELF", "SENM" }).Contains(cb.TIPO) && cb.VALOR != 0
group cb by new { cb.TIPO, cb.CODIGO_DEPENDENCIA } into cbg
select new { cbg.Key.CODIGO_DEPENDENCIA,
LOCAL_MOVEL = (cbg.Key.TIPO == "SELM" ? cbg.SUM(cb => cb.VALOR) : null),
LOCAL_FIXO = (cbg.Key.TIPO == "SELF" ? cbg.SUM(cb => cb.VALOR) : null),
DDD_MOVEL = (cbg.Key.TIPO == "SENM" ? cbg.SUM(cb => cb.VALOR) : null),
DDD_FIXO = (cbg.Key.TIPO == "SENF" ? cbg.SUM(cb => cb.VALOR) : null),
EXTERNA_INTERNACIONAL = (cbg.Key.TIPO == "SEI" ? cbg.SUM(cb => cb.VALOR) : null),
};
var ans = from cb in tab
group cb by cb.CODIGO_DEPENDENCIA into cbg
select new {
CODIGO_DEPENDENCIA = cbg.Key,
LOCAL_MOVEL = cbg.Sum(cb => cb.LOCAL_MOVEL == null ? 0 : cb.LOCAL_MOVEL),
LOCAL_FIXO = cbg.Sum(cb => cb.LOCAL_FIXO == null ? 0 : cb.LOCAL_FIXO),
DDD_MOVEL = cbg.Sum(cb => cb.DDD_MOVEL == null ? 0 : cb.DDD_MOVEL),
DDD_FIXO = cbg.Sum(cb => cb.DDD_FIXO == null ? 0 : cb.DDD_FIXO),
EXTERNA_INTERNACIONAL = cbg.Sum(cb => cb.EXTERNA_INTERNACIONAL == null ? 0 : cb.EXTERNA_INTERNACIONAL)
};

Linq Left Outer Join C#

I have been working with this linq query for a while. I have looked at a ton of answers on stackoverflow and beyond. I have tried many solutions and read up on just as many. The code below is 2 of my numerous attempts to create this inner join the error that I am getting is
Object reference not set to an instance of the object
Attempt A
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w.Company,
BrandName = w.Brand,
CampaignName = w.Name,
Channel = z.Type,
Wave = "",
CampaignId = w.Id,
ActivityDate = cr.ResponseDate,
Activity = "",
Unsubscribed = cr.Unsubscribed,
Responded = cr.Responded,
Clicked = cr.Clicked,
Viewed = cr.Viewed,
Sent = cr.Sent,
Targeted = cr.Targeted,
HardBounced = cr.HardBounced,
SoftBounced = cr.SoftBounced,
WasTargeted = cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z.Id,
CampaignWaveId = "J" + x.Id,
ContactId = cr.ContactId,
AtTaskId = w.AtTaskId,
LinkClicked = cr.Referrer,
OptTopic = z.TopicId,
DiseaseState = "",
ElementDescription = y.Name,
WaveDescription = x.Label
};
Attempt B
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = x == null ? null : w.Company,
BrandName = x == null ? null : w.Brand,
CampaignName = x == null ? null : w.Name,
Channel = x == null ? null : z.Type,
Wave = "",
CampaignId = x == null ? null : w.Id,
ActivityDate = x == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = x == null ? null : cr.Unsubscribed,
Responded = x == null ? null : cr.Responded,
Clicked = x == null ? null : cr.Clicked,
Viewed = x == null ? null : cr.Viewed,
Sent = x == null ? null : cr.Sent,
Targeted = x == null ? null : cr.Targeted,
HardBounced = x == null ? null : cr.HardBounced,
SoftBounced = x == null ? null : cr.SoftBounced,
WasTargeted = x == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = x == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = x == null ? null : cr.ContactId,
AtTaskId = x == null ? null : w.AtTaskId,
LinkClicked = x == null ? null : cr.Referrer,
OptTopic = x == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = x == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
Attempt C
var records = from cr in lstContactResponse
join jn in lstJourneyNodeData on cr.GrandparentId equals jn.Id into a
from x in a.DefaultIfEmpty()
join j in lstJourney on x.JourneyId equals j.Id into b
from y in b.DefaultIfEmpty()
join ce in lstCampaignElement on y.Name equals ce.LinkedJourney into c
from z in c.DefaultIfEmpty()
join c in lstCampaign on z.CampaignId equals c.Id into d
from w in d.DefaultIfEmpty()
select new JourneyRecord
{
CompanyName = w == null ? null : w.Company,
BrandName = w == null ? null : w.Brand,
CampaignName = w == null ? null : w.Name,
Channel = z == null ? null : z.Type,
Wave = "",
CampaignId = w == null ? null : w.Id,
ActivityDate = cr == null ? null : cr.ResponseDate,
Activity = "",
Unsubscribed = cr == null ? null : cr.Unsubscribed,
Responded = cr == null ? null : cr.Responded,
Clicked = cr == null ? null : cr.Clicked,
Viewed = cr == null ? null : cr.Viewed,
Sent = cr == null ? null : cr.Sent,
Targeted = cr == null ? null : cr.Targeted,
HardBounced = cr == null ? null : cr.HardBounced,
SoftBounced = cr == null ? null : cr.SoftBounced,
WasTargeted = cr == null ? null : cr.WasTargeted,
Email = "",
Id = "",
CampaignElementId = z == null ? null : z.Id,
CampaignWaveId = "J" + (x == null ? null : x.Id),
ContactId = cr == null ? null : cr.ContactId,
AtTaskId = w == null ? null : w.AtTaskId,
LinkClicked = cr == null ? null : cr.Referrer,
OptTopic = z == null ? null : z.TopicId,
DiseaseState = "",
ElementDescription = y == null ? null : y.Name,
WaveDescription = x == null ? null : x.Label
};
Of course there is a way to do that in LINQ. If you have answered my questions in the comment, I would provide you the exact solution, now I'll just give you an example. The technique is different for LINQ to Objects vs LINQ to Entities, so the following apply for LINQ to Objects.
The solution is to check for null every property involved in the right side of the left join, including the further joins. Also value type properties needs to be converted to nullable (that's why it was important to have your classes - for prior C#6 code).
Here is the example:
Having the following "tables"
var t1 = new[]
{
new { Id = 1 , Name = "A", Date = DateTime.Today },
new { Id = 2 , Name = "B", Date = DateTime.Today},
new { Id = 3 , Name = "C", Date = DateTime.Today},
};
var t2 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A1", Date = DateTime.Today },
new { Id = 2 , ParentId = 2, Name = "B1", Date = DateTime.Today },
};
var t3 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A11", Date = DateTime.Today },
new { Id = 2 , ParentId = 1, Name = "A12", Date = DateTime.Today },
};
var t4 = new[]
{
new { Id = 1 , ParentId = 1, Name = "A111", Date = DateTime.Today },
};
Pre C#6
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2 != null ? (int?)e2.Id : null equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3 != null ? (int?)e3.Id : null equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2 != null ? (int?)e2.Id : null,
t2_Name = e2 != null ? e2.Name : null,
t2_Date = e2 != null ? (DateTime?)e2.Date : null,
t3_Id = e3 != null ? (int?)e3.Id : null,
t3_Name = e3 != null ? e3.Name : null,
t3_Date = e3 != null ? (DateTime?)e3.Date : null,
t4_Id = e4 != null ? (int?)e4.Id : null,
t4_Name = e4 != null ? e4.Name : null,
t4_Date = e4 != null ? (DateTime?)e4.Date : null,
};
var result = query.ToList();
Looks ugly, but works.
C#6 - The same result is achieved by simply adding ? before any right side property accessor (repeat - including join conditions)
var query =
from e1 in t1
join e2 in t2 on e1.Id equals e2.ParentId into g2
from e2 in g2.DefaultIfEmpty()
join e3 in t3 on e2?.Id equals e3.ParentId into g3
from e3 in g3.DefaultIfEmpty()
join e4 in t4 on e3?.Id equals e4.Id into g4
from e4 in g4.DefaultIfEmpty()
select new
{
t1_Id = e1.Id,
t1_Name = e1.Name,
t1_Date = e1.Date,
t2_Id = e2?.Id,
t2_Name = e2?.Name,
t2_Date = e2?.Date,
t3_Id = e3?.Id,
t3_Name = e3?.Name,
t3_Date = e3?.Date,
t4_Id = e4?.Id,
t4_Name = e4?.Name,
t4_Date = e4?.Date,
};
var result = query.ToList();
There was no way with Linq that I was able to determine to accomplish what I had wanted to do. Therefore I went another direction with the solution to the problem.
foreach (ContactResponse cr in lstContactResponse)
{
ContactResponseRecord crr = new ContactResponseRecord() {
ContactId = cr.ContactId,
ActivityDate = cr.ResponseDate,
LinkClicked = cr.Referrer};
var vJourneyNodeData = from x in lstJourneyNodeData where x.Id == cr.GrandparentId select x;
if(null != vJourneyNodeData && vJourneyNodeData.Count() > 0)
{
jnd = vJourneyNodeData.FirstOrDefault();
crr.CampaignWaveId = "J" + jnd.Id;
crr.WaveDescription = jnd.Label;
}
var vJourney = from x in lstJourney where x.Id == jnd.JourneyId select x;
if (null != vJourney && vJourney.Count() > 0)
{
j = vJourney.FirstOrDefault();
crr.OptTopic = j.TopicId;
}
var vCampaignElement = from x in lstCampaignElement where x.LinkedJourney == j.Name select x;
if (null != vCampaignElement && vCampaignElement.Count() > 0)
{
ce = vCampaignElement.FirstOrDefault();
crr.Ccg_Id = ce.CCGId;
crr.ElementDescription = ce.Description.ToString();
crr.CampaignElementId = ce.Id;
var vCampaign = from x in lstCampaign where x.Id == ce.CampaignId select x;
if (null != vCampaign && vCampaign.Count() > 0)
{
c = vCampaign.FirstOrDefault();
crr.ActivityDate = c.AtTaskId;
crr.BrandName = c.Brand;
crr.CampaignId = c.Id;
crr.CampaignName = c.Name;
crr.CompanyName = c.Company;
}
}

LINQ2SQL doesn't return row if checking with null

I have following LINQ2SQL Query:
var map =
dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == tcpDms.FacilityId &&
c.DriverControlledParameterId == controlledParamId &&
c.DriverValue == value);
All the types are string.
In my DB i have a row, which must be returned by query.
When value="0", controlledParamId =null and FacilityId ="abc" this query returns null, but when i wrote following:
var test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == null &&
c.DriverValue == "0");
test was not null
What am i doing wrong?
P.S. I also tried c.DriverControlledParameterId.Equals(controlledParamId) but it also doesn't work.
The problem is, that LINQ2SQL has a special handling for the expression c.DriverControlledParameterId == null. It is translated to the SQL DriverControlledParameterId IS NULL.
But c.DriverControlledParameterId = controlledParamId is translated to the SQL DriverControlledParameterId = :p1, even when controlledParamId is null. And in SQL DriverControlledParameterId = NULL is undefined and as such never TRUE.
How to fix: Handle the null case specifically:
TCPDriverMapping test;
if(controlledParamId == null)
test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == null &&
c.DriverValue == "0");
else
test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
c.DriverControlledParameterId == controlledParamId &&
c.DriverValue == "0");
Or like this:
var test = dbContext.TCPDriverMappings.FirstOrDefault(
c => c.DriverFacilityId == "abc" &&
((controlledParamId == null &&
c.DriverControlledParameterId == null) ||
c.DriverControlledParameterId == controlledParamId) &&
c.DriverValue == "0");
Or like this:
IQueryable<TCPDriverMapping> query =
dbContext.TCPDriverMappings.Where(c => c.DriverFacilityId == "abc" &&
c.DriverValue == "0");
if(controlledParamId == null)
query = query.Where(c => c.DriverControlledParameterId == null);
else
query = query.Where(c => c.DriverControlledParameterId == controlledParamId);
var test = query.FirstOrDefault();
That third option is what I would use. In my opinion, this is the more readable than option 2 and has no repeated code like the first one.

Categories