I'm trying to do a left outer join with linq on on 2 Lists of the same type. I've been following the syntax I see in examples online, but my left join is ending up with a count of 0 values. The 2 lists being joined are not empty so I should definitely be getting some results however I can't seem to determine what is wrong with the syntax. Any help would be greatly appreciated.
var leftOuterJoin = from r in received
join rs in reserved.DefaultIfEmpty()
on new {a = r.ProductId, b = r.WarehouseSectionId } equals new { a = rs.ProductId, b = rs.WarehouseSectionId } into joinedL
from rs in joinedL.DefaultIfEmpty()
select new
{
SKU = r.SKU,
ProductName = r.ProductName,
QTY = r.QTY,
PhysicalStock = (rs.QTY != null && rs.QTY > 0) ? r.QTY + rs.QTY : r.QTY,
WarehouseSection = r.WarehouseSection,
WarehouseName = r.WarehouseName,
ProductId = r.ProductId,
WarehouseSectionId = r.WarehouseSectionId
};
Edit:
I am able to make the query return values by commenting out Physical Stock in the select but I can still not figure out a reason for this. It looks like this error is caused by using the rs.qty variable, if I change any of the fields to rs.qty, it will trigger the same error. All of the rs.qty fields have values however there are more r items than rs items
//PhysicalStock = (rs.QTY != null && rs.QTY > 0) ? r.QTY + rs.QTY : r.QTY,
I managed to fix this problem. The issue was with this line:
PhysicalStock = (rs.QTY != null && rs.QTY > 0) ? r.QTY + rs.QTY : r.QTY,
Instead of doing the null check on qty I should have been doing the null check on rs to make sure the object was not null
Fix:
PhysicalStock = rs != null ? rs.QTY + r.QTY : r.QTY,
Related
pdlist = (from a in context.EMPLOYEES
join b in context.PERSONS on a.PERSON_ID equals b.PERSON_ID
where a.SUPERVISOR_ID == empId
select new Pollidut.Models.Pollidut
{
PollidutId = a.EMPLOYEE_ID,
PollidutName = b.PERSON_NAME,
DistributionHouseId = a.DISTRIBUTION_HOUSE_ID == null ? 0 : (int)a.DISTRIBUTION_HOUSE_ID
}).ToList();
DateTime dt = DateTime.Now.Date;
var pdTargets = (from p in context.PALLYDUT_TARGET
where p.Active == true && p.StartDate <= dt && p.EndDate >= dt
group p by p.PallydutId into g
select new
{
PollidutId = g.Key,
Start = g.Select(x => x.StartDate).Min(),
End = g.Select(y => y.EndDate).Max(),
Target = g.Select(z => z.Target).Sum()
}).ToList();
var PdTargetsList = (from m in pdlist
join n in pdTargets on m.PollidutId equals n.PollidutId into t
from l in t.DefaultIfEmpty()
select new
{
PallydutId = m.PollidutId,
PallydutName = m.PollidutName,
DistributionId = m.DistributionHouseId,
StartDate = l.Start == null ? dt : l.Start,
EndDate = l.End == null ? dt : l.End,
Target = l.Target == null ? 0 : l.Target
}).ToList();
pdlist is employee list where pdTarget may set or not. pdTarget can be empty. When I left join pdlist with pdTargets I get Object reference not set error. pdTargets collection returns null.How to fix it. Anybody helps me greatly appreciated.
The reason I suspect why you are getting a Null reference exception is because your are directly accessing the properties on a null object (l in your case), even though you are using a DefaultIfEmpty() method which is going to return null if no matching rows are found. You should change your code like this:-
select new
{
PallydutId = m.PollidutId,
PallydutName = m.PollidutName,
DistributionId = m.DistributionHouseId,
StartDate = l == null ? dt : l.Start,
EndDate = l == null ? dt : l.End,
Target = l == null ? 0 : l.Target
}).ToList();
Also, If you think that your one object pdTarget can be null, then I don't think its about a left join or a normal join, your code will throw an exception in either case. Please check this MSDN documentation to handle nulls in query expressions.
Here is the full query(without the where), that works:
public List<TipoResiduo> filtro(TipoResiduo objent)
{
using (var db = new DBEntities())
{
var consulta = (from a in db.tb006_tipo_residuo
join cr in db.tb016_classe_residuo on a.fk_id_classe_residuo equals cr.id into trcr
from classeresiduo in trcr.DefaultIfEmpty()
join gr in db.tb017_grupo_residuo on a.fk_id_grupo_residuo equals gr.id into trgr
from gruporesiduo in trgr.DefaultIfEmpty()
join tfg in db.tb008_tipo_fonte_geradora on a.fk_id_tipo_fonte_geradora equals tfg.id into trtfg
from tipofontegeradora in trtfg.DefaultIfEmpty()
join civig in db.tb051_categoria_ivig on a.fk_id_categoria_ivig equals civig.id into trci
from categoriaivig in trci.DefaultIfEmpty()
join icap in db.tb048_ibama_capitulo on a.fk_id_ibama_capitulo equals icap.id into tric
from ibamacapitulo in tric.DefaultIfEmpty()
join isubcap in db.tb049_ibama_subcapitulo on a.fk_id_ibama_subcapitulo equals isubcap.id into tris
from ibamasubcapitulo in tris.DefaultIfEmpty()
join ires in db.tb050_ibama_residuo on a.fk_id_ibama_residuo equals ires.id into trir
from ibamaresiduo in trir.DefaultIfEmpty()
//where a.fk_id_classe_residuo == objent.fk_id_classe_residuo
select new TipoResiduo()
{
id = a.id,
no_tipo_residuo = a.no_tipo_residuo,
dt_cadastro = a.dt_cadastro,
fk_id_classe_residuo = a.fk_id_classe_residuo,
fk_id_grupo_residuo = a.fk_id_grupo_residuo,
nu_densidade = a.nu_densidade,
fk_id_tipo_fonte_geradora = a.fk_id_tipo_fonte_geradora,
fk_id_categoria_ivig = a.fk_id_categoria_ivig,
fk_id_ibama_capitulo = a.fk_id_ibama_capitulo,
fk_id_ibama_subcapitulo = a.fk_id_ibama_subcapitulo,
fk_id_ibama_residuo = a.fk_id_ibama_residuo,
no_classe_residuo = classeresiduo == null ? String.Empty : classeresiduo.no_classe_residuo,
no_grupo_residuo = gruporesiduo == null ? String.Empty : gruporesiduo.no_grupo_residuo,
no_tipo_fonte_geradora = tipofontegeradora == null ? String.Empty : tipofontegeradora.no_tipo_fonte_geradora,
no_categoria_ivig = categoriaivig == null ? String.Empty : categoriaivig.no_categoria_ivig,
no_ibama_capitulo = ibamacapitulo == null ? String.Empty : ibamacapitulo.de_ibama_capitulo,
no_ibama_subcapitulo = ibamasubcapitulo == null ? String.Empty : ibamasubcapitulo.de_ibama_subcapitulo,
no_ibama_residuo = ibamaresiduo == null ? String.Empty : ibamaresiduo.de_ibama_residuo
});
return consulta.OrderBy(a => a.no_tipo_residuo).ToList();
}
}
My object TipoResiduo has some virtual fields just for convenience and can have some null fields.
And when I try to filter with the where(removing the //) the query shows nothing. The ObjEnt of the function has some fields previously populated, and when the field is null, I want to show all.
I tried this too, and nothing:
where a.fk_id_classe_residuo ==
(objent.fk_id_classe_residuo == null
? 0 : objent.fk_id_classe_residuo)
I'm new at this, what should I do to make this work?
You have no left outer join so I don't understand the title
If objent.fk_id_classe_residuo is null this will find a.fk_id_classe_residuo = 0 - not all
where a.fk_id_classe_residuo == (objent.fk_id_classe_residuo == null ? 0 : objent.fk_id_classe_residuo)
try this
where objent.fk_id_classe_residuo == null
or a.fk_id_classe_residuo == objent.fk_id_classe_residuo
After hitting my head into the wall, I found the answer:
where objent.fk_id_classe_residuo == 0 ? true : classeresiduo.id == null
&& classeresiduo.id == null ? false : a.fk_id_classe_residuo == objent.fk_id_classe_residuo
The problem is this objent.fk_id_classe_residuo comes from a dropdownlist, and I set this fk_id as 0 when no option is given. Well, would be very difficult to someone help me with this. :|
But I thank Blam for his attention. ;)
Ok, so I'm trying to turn this:
sSelect = "SELECT CONVERT(VARCHAR, CommitDate, 101) AS XLabel, " +
"SUM(CASE WHEN NOT CompletionDate IS NULL THEN 1 ELSE 0 END) AS ClosedEvents, " +
"COUNT(CommitDate) AS Total, " +
"COUNT(CommitDate) - SUM(CASE WHEN NOT CompletionDate IS NULL THEN 1 ELSE 0 END) AS OpenEvents, " +
"SUM(CASE WHEN CompletionDate IS NULL AND commitdate < Convert(varchar(12),getdate(),101) THEN 1 ELSE 0 END) AS BehindSchedule";
into a Linq query. So far I've got:
var vEventsEntriesEnum = dtEventsEntries.AsEnumerable();
var vOpenEntriesData = from r in vEventsEntriesEnum
select new
{
XLabel = r["CommitDate"],
ClosedEvents = vEventsEntriesEnum.Sum(closed => (closed["CompletionDate"] != null) ? 1 : 0),
Total = vEventsEntriesEnum.Count(total => (total["CommitDate"] != null) ? true : false),
OpenEvents = Total - ClosedEvents,
};
which is where I realized I might have a problem. Total and ClosedEvents do not exist in that context.
While I can just go ahead and repeat the queries for ClosedEvents and Total and cast then subtract them or whatever, I was hoping there'd be a better way.
If there are any other ways of doing what I'm doing with the rest of the code, feel free to let me know.
Any ideas?
You have to materialize it somewhere. In query syntax you can use the let clause:
var vOpenEntriesData = from r in vEventsEntriesEnum
let ClosedEvents = vEventsEntriesEnum.Sum(closed => (closed["CompletionDate"] != null) ? 1 : 0)
select new
{
XLabel = r["CommitDate"],
ClosedEvents,
Total = vEventsEntriesEnum.Count(total => (total["CommitDate"] != null) ? true : false),
OpenEvents = Total - ClosedEvents,
};
This is similar to a variable in a loop.
I am trying to grab all data from FDerive, however I am try to set a filter with a where clause. Unfortunately I am getting a nullreferencexpection when I touch spd when a row in spd is null.
var Result = from fpd in FDerive
join spd in SDerive
on new { fpd.PId, fpd.SId }
equals new { spd.PId, spd.SId } into allRows
from spd in allRows.DefaultIfEmpty()
where spd.SId == ""
|| spd.PId == ""
select new { fpd, spd };
How do I get around the null error?
DefaultIfEmpty<T> will return a set containing only one element with the default value of T - in this case null - if the source collection is empty. So spd will be null if there are no items returned in the join.
Try to a null check in the where clause
var Result =
...
where spd == null || spd.SId == "" || spd.PId == ""
select new { fpd, spd };
I found the answer at the bottom of the code in the following question
LINQ double left join
var results =
from person in students
join entry in subquery on person.FullName equals entry.AuthorFullName into personEntries
from personEntry in personEntries.DefaultIfEmpty()
orderby person.FullName
select new
{
PersonName = person.FullName,
BlogTitle = personEntry == null ? "" : personEntry.Title
};
I have very complex linq query which is working fine for inner join, i.e., without z_temp.DefaultIfEmpty(). But when I use this for left join, The query is not yielding results.
var q = from x in db.EmployeesList
where x.EmployeesListStartDate >= startDate && x.EmployeesListStartDate <= endDate
join y in db.Survey on x.Survey.SurveyID equals y.SurveyID
join z in
(from a in db.Commit
join b in
(from commit in db.Commit
where
commit.CommitListID != null &&
commit.CommitType.ToUpper() != "PREVIEW"
group commit by new
{
commit.CommitListID
} into g
select new
{
CommitListID = (Int32?)g.Key.CommitListID,
CommitId = (Int32?)g.Max(p => p.CommitId)
})
on new { a.CommitListID, a.CommitId }
equals new { b.CommitListID, CommitId = (Int32)b.CommitId }
select new
{
CommitListID = (Int32?)a.CommitListID,
CommitUsername= a.CommitUsername,
CommitStartDateTime=a.CommitStartDateTime,
CommitType=a.CommitType,
CommitSuccessCount=a.CommitSuccessCount
}) on new { EmployeesListID = x.EmployeesListID } equals new { EmployeesListID = (Int32)z.CommitListID }
into z_temp
from _z in z_temp.DefaultIfEmpty()
select new CustomEmployeesList
{
SurveyId = x.Survey.SurveyID != null ? (int)x.Survey.SurveyID : 0,
EmployeesListId = x.EmployeesListID != null ? (int)x.EmployeesListID : 0,
EmployeesListName = x.EmployeesListName,
SpecificMessage = x.SpecificMessage,
ListCriteria = x.ListCriteria,
Channel = x.Channel,
EmployeesListStartDate = (DateTime)x.EmployeesListStartDate,
EmployeesListEndDate = (DateTime)x.EmployeesListEndDate,
Records = x.Records != null ? (int)x.Records : 0,
QueryId = x.AppSqlQueries.QueryId != null ? (int)x.AppSqlQueries.QueryId : 0,
//AuditId = (Int32?)x.AuditEntry.AuditId,
StatusCommonCode = x.CommonCode.CommonCodeId != null ? (int)x.CommonCode.CommonCodeId : 0,
SurveyName = y.SurveyName,
LastCommitDateTime = _z.CommitStartDateTime.HasValue ? (DateTime)_z.CommitStartDateTime : DateTime.MinValue,
LastCommitType = _z.CommitType != null ? _z.CommitType : "",
LastCommitUsername = _z.CommitUsername != null ? _z.CommitUsername : "",
LastCommitCount = _z.CommitSuccessCount.HasValue ? (int)_z.CommitSuccessCount : 0
};
This is returning no results and
I am getting this exception message while viewing results in debug mode:
LINQ to Entities does not recognize the method
'System.Collections.Generic.IEnumerable1[<>f_AnonymousType351[<>f_AnonymousType35%5bSystem.Nullable1[System.Int32],System.String,System.Nullable1%5bSystem.DateTime%5d,System.String,System.Nullable`1%5bSystem.Int32%5d%5d%5d">System.Nullable1[System.Int32],System.String,System.Nullable1[System.DateTime],System.String,System.Nullable1[System.Int32]]]
DefaultIfEmpty[<>f__AnonymousType35' method, and this method cannot be
translated into a store expression.
Can anyone suggest the where the problem would be, this would be really helpful!
The problem is in this line:
from _z in z_temp.DefaultIfEmpty()
Calling DefaultIfEmpty() will return null if no rows matches the join. Ok, you a left join, but you have to test if _z is null before access its members:
...
LastCommitDateTime = _z == null ? DateTime.MinValue : (_z.CommitStartDateTime.HasValue ? (DateTime)_z.CommitStartDateTime : DateTime.MinValue),
LastCommitType = _z == null ? "" : (_z.CommitType != null ? _z.CommitType : ""),
...
etc.
A more elegant alternative is create a class that defines the fields you want and call _z.DefaultIfEmpty(new ZRow()), so you don't need to test if _z is null every time you need it. But in this case you'll need to change the select that produces the result for z_temp and replace it to select new ZRow(a.CommitListID, etc..). Not a big deal.