I wrote the below sql query
SELECT *
FROM dbo.PR_ADDRESS LEFT OUTER JOIN
dbo.Book_MarkText ON dbo.PR_ADDRESS.GroupID = dbo.Book_MarkText.BMData
where
dbo.PR_ADDRESS.GroupID = dbo.Book_MarkText.BMData
OR
PR_ADDRESS.GroupID in ('001','002','003')
to LINQ as
string[] srGroupIDs = new string[] { "001", "002", "003" };
var objResult =
(from PR_ADDRESS in dtPR_ADDRESS.AsEnumerable()
join
Book_MarkText in dtBookmarkText.AsEnumerable() on
(string)PR_ADDRESS["GroupID"] equals (string)Book_MarkText["BMData"]
into Book_MarkText_join
from Book_MarkText_Temp in Book_MarkText_join.DefaultIfEmpty()
where srGroupIDs.Contains(PR_ADDRESS["Groupid"])
|| ((string)PR_ADDRESS["Groupid"] == (string)Book_MarkText_Temp["BMData"])
select new
{
ID = PR_ADDRESS["ID"],
Name1 = PR_ADDRESS["Name1"]
}).ToList();
But Gives me null reference exception on line
where srGroupIDs.Contains(PR_ADDRESS["Groupid"])
|| ((string)PR_ADDRESS ["Groupid"] == (string)Book_MarkText_Temp["BMData"])
Why ?
If i remove .DefaultIfEmpty() , this works without exception , but i need 'LEFT OUTER JOIN' so can't remove .DefaultIfEmpty() . How can i solve it ?
Edit :-
I added the OR case also , Hope now it is clear
Solved by handling Book_MarkText_Temp null as Jon Skeet's comment .Thanks for finding time to help me .
string[] srGroupIDs = new string[] { "001", "002", "003" };
var objResult =
(from PR_ADDRESS in dtPR_ADDRESS.AsEnumerable()
join
Book_MarkText in dtBookmarkText.AsEnumerable() on
(string)PR_ADDRESS ["GroupID"] equals (string)Book_MarkText["BMData"] into Book_MarkText_join
from Book_MarkText_Temp in Book_MarkText_join.DefaultIfEmpty()
where Book_MarkText_Temp == null ? srGroupIDs.Contains(PR_ADDRESS["Groupid"]) :
srGroupIDs.Contains(PR_ADDRESS["Groupid"])
|| ((string)PR_ADDRESS["Groupid"] == (string)Book_MarkText_Temp["BMData"])
select new {
ID = PR_ADDRESS ["ID"],
Name1 = PR_ADDRESS ["Name1"]
}).ToList();
Related
Im trying to do a left join in Linq joining two different list as you can see below:
var fab = (from a in lstt
join b in lstt2 on new { a.PO, a.Line } equals new { b.PO, b.Line } into newab
from ab in newab.DefaultIfEmpty()
select new BomFabConcentrado
{
PO = a.PO,
Line = a.Line,
Fabric1 = ab.Fabric1
}).ToList();
The problem is that the result of ab is null and I got the following error message:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
ab was null.
As extra information lstt contains 900 elements and lstt contains 200.
Does anyone know what is wrong?
Thanks for you help.
Left join use following query
var fab = (from a in lstt
join b in lstt2 on new { a.PO, a.Line } equals new { b.PO, b.Line } into newab
from ab in newab.DefaultIfEmpty()
select new BomFabConcentrado
{
PO = a.PO,
Line = a.Line,
Fabric1 = (ab == null || ab.Fabric1 == null) ? 0 : ab.Fabric1
//or use
Fabric1 = ab?.Fabric1 ?? 0
}).ToList();
Add a null check to your lists. For example like this:
lstt = lstt.Where(a => a != null).ToList();
lstt2 = lstt2.Where(b => b != null).ToList();
var fab = (from a in lstt
join b in lstt2 on new { a.PO, a.Line } equals new { b.PO, b.Line }
into newab
from ab in newab.DefaultIfEmpty()
select new BomFabConcentrado
{
PO = a.PO,
Line = a.Line,
Fabric1 = ab.Fabric1
}).ToList();
I have two datatables,
var userList1 = from myRow in dt.AsEnumerable()
where myRow.Field<bool?>("IsActive1") == null
? true
: myRow.Field<bool?>("IsActive1") == true
select myRow;
var userList2 = from myRow in dt1.AsEnumerable()
select myRow;
dt1 table shows like this,
Using this Linq query,
var objUserSetUp1 = (from A in userList1
join B in userList2
on new
{
UserId = A.Field<Int64?>("Id") == null
? 0
: A.Field<Int64>("Id")
}
equals new
{
UserId = B.Field<Int64?>("UserId") == null
? 0
: B.Field<Int64>("UserId")
}
select new
{
UserId = A.Field<Int64>("Id"),
FirstName = A.Field<string>("FirstName"),
SurName = A.Field<string>("SurName"),
Computer_Name = A.Field<string>("Computer_Name"),
IP_Address = A.Field<string>("IP_Address"),
LogInTime = A.Field<string>("LogInTime") == null
? "UnKnown"
: A.Field<string>("LogInTime"),
UserName = A.Field<string>("UserName"),
Password = A.Field<string>("Password"),
login_Id = A.Field<Int64?>("login_Id") == null
? 0 :
A.Field<Int64?>("login_Id"),
docCount = B.Field<Int64>("docCount")
}).ToList();
How can I get if UserId is null also want to take docCout field value too. How can I do this inside the query?
I think you need a Left Outer Join, where the default value for the outer join (ie when no matching record exists) is the userList2 entry where Field("UserId") is null.
See below (untested, but you get the idea!):
var objUserSetUp1 = (from A in userList1
join B in userList2
on A.Field<Int64?>("Id") equals B.Field<Int64?>("UserId")
into BGroup
from C in BGroup.DefaultIfEmpty(userList2.Single(u => u.Field<Int64?>("UserId") == null))
select new
{
UserId = A.Field<Int64>("Id"),
FirstName = A.Field<string>("FirstName"),
SurName = A.Field<string>("SurName"),
Computer_Name = A.Field<string>("Computer_Name"),
IP_Address = A.Field<string>("IP_Address"),
LogInTime = A.Field<string>("LogInTime") == null
? "UnKnown"
: A.Field<string>("LogInTime"),
UserName = A.Field<string>("UserName"),
Password = A.Field<string>("Password"),
login_Id = A.Field<Int64?>("login_Id") == null
? 0 :
A.Field<Int64?>("login_Id"),
docCount = C.Field<Int64>("docCount")
}).ToList();
I am developing a query to grab and join some SQL tables in C# and am having some trouble with grouping and enumerables within the dataset. My query is below. This gives me the data in the format I'm looking for, but it takes way too long when I try to add the enumerated list as indicated below. When I look under the hood I can see it is executing way too many SQL queries. I'd like to get it to just one. Using LinqPad:
void Main()
{
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
orderby a.StartTime
group new {a, b} by new
{
a.TestGuid,
a.Name,
a.Description,
a.StartTime,
a.Duration,
a.NumAgents,
a.NumHosts,
a.PassFail,
a.ResultsFilePath,
a.Splunk
}
into g
let scenarioStart = g.Min(s => s.a.StartTime) ?? g.Min(s => s.a.DateCreated)
let testCases = g.Select(s => s.b)
orderby scenarioStart
select new
{
TestGuid = g.Key.TestGuid,
ScenarioRun = new
{
Name = g.Key.Name,
Description = g.Key.Description,
StartTime = scenarioStart,
Duration = g.Key.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = g.Key.NumHosts,
Result = g.Key.PassFail,
ResultsFilePath = g.Key.ResultsFilePath,
SplunkLink = g.Key.Splunk,
// PROBLEM: Causes too many queries:
TestRuns = from t in testCases select t.TestCaseId
}
}).ToLookup(g => g.TestGuid, g => g.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();
}
The "TestRuns" line is causing the excessive queries. Any idea what I am doing wrong here?
Thanks for any insight.
Tough answer to test but I think we can avoid the grouping and multiple queries with something like this: (https://msdn.microsoft.com/en-us/library/bb311040.aspx)
var nightlyRuns = (from a in LoadTestSummaries
join b in LoadTestTestSummaryData
on a.LoadTestRunId equals b.LoadTestRunId
where a.TargetStack == "LoadEnv" &&
a.TestGuid != null &&
a.StartTime != null &&
a.LoadTestRunId != null
into testGroup
select new
{
TestGuid = a.TestGuid,
ScenarioRun = new
{
Name = a.TestGuid,
Description = a.Description,
StartTime = a.StartTime ?? a.DateCreated,
Duration = a.Duration,
NumAgents = g.Key.NumAgents,
NumHosts = a.NumHosts,
Result = a.PassFail,
ResultsFilePath = a.ResultsFilePath,
SplunkLink = a.Splunk,
// PROBLEM: Causes too many queries:
TestRuns =testGroup
}
}).OrderBy(x=>x.StartTime).ToLookup(x => x.TestGuid, x => x.ScenarioRun);
nightlyRuns["ba593f66-695f-4fd1-99c3-71253a2e4981"].Dump();
I have two LinqToSql queries that return result sets:
var grResults = (from g in ctx.GeneralRequests
join rt in ctx.RequestTypes on g.RequestTypeId equals rt.RequestTypeId
join sub in ctx.Logins on g.SubmitterStaffId equals sub.LoginId
join onb in ctx.Logins on g.OnBehalfOfStaffId equals onb.LoginId
where sub.GadId == gadId
select new
{
Status = "Submitted",
RequestId = g.GeneralRequestId,
Submitter = sub.UserName,
OnBehalf = (onb == null ? string.Empty : onb.UserName),
RequestType = (rt == null ? string.Empty : rt.Description),
ProjectName = (g == null ? string.Empty : g.ProjectName) ,
Comments = (g == null ? string.Empty : g.Comments),
LastUpdate = g.LastUpdateDate
});
var grdResults = (from gd in ctx.GeneralRequestDrafts
join rt in ctx.RequestTypes on gd.RequestTypeId equals rt.RequestTypeId
into tempRequestTypes
from rt1 in tempRequestTypes.DefaultIfEmpty()
join onb in ctx.Logins on gd.OnBehalfOfStaffId equals onb.LoginId
into tempOnBehalf
from onb1 in tempOnBehalf.DefaultIfEmpty()
join sub in ctx.Logins on gd.SubmitterStaffId equals sub.LoginId
where sub.GadId == gadId
select new
{
Status = "Draft",
RequestId = gd.GeneralRequestDraftId,
Submitter = sub.UserName,
OnBehalf = (onb1 == null ? string.Empty : onb1.UserName),
RequestType = (rt1 == null ? string.Empty : rt1.Description),
ProjectName = (gd.ProjectName == null ? string.Empty : gd.ProjectName),
Comments = (gd.Comments == null ? string.Empty : gd.Comments),
LastUpdate = gd.LastUpdateDate
});
The problem is when I try to Union them.
var results = grResults.Union(grdResults).OrderByDescending(r => r.LastUpdate);
This returns no records even though the two individual queries do.
Since the 2 queries don't appear to rely on each other just execute both and union the results of each if you are just trying to get a single list.
var results = grResults.ToList().Union(grdResults.ToList())
.OrderByDescending(r => r.LastUpdate);
I'm writing two LINQ queries where I use my first query's result set in my second query.
But in some cases when there is no data in the database table my first query returns null,
and because of this my second query fails since wsdetails.location and wsdetails.worklocation are null causing an exception.
Exception:
Object reference not set to an instance of an object
My code is this:
var wsdetails = (from assetTable in Repository.Asset
join userAsset in Repository.UserAsset on
assetTable.Asset_Id equals userAsset.Asset_Id
join subLocationTable in Repository.SubLocation on
assetTable.Sub_Location_Id equals subLocationTable.Sub_Location_ID
where userAsset.User_Id == userCode
&& assetTable.Asset_TypeId == 1 && assetTable.Asset_SubType_Id == 1
select new { workstation = subLocationTable.Sub_Location_Name, location = assetTable.Location_Id }).FirstOrDefault();
result = (from emp in this.Repository.Employee
join designation in this.Repository.Designation on
emp.DesignationId equals designation.Id
where emp.Code == userCode
select new EmployeeDetails
{
firstname = emp.FirstName,
lastname = emp.LastName,
designation = designation.Title,
LocationId = wsdetails.location,
WorkStationName = wsdetails.workstation
}).SingleOrDefault();
As a workaround I can check
if wsdetails == null
and change my second LINQ logic, but I believe there are some ways to handle null values in LINQ itself like the ?? operator.
But I tried this and it didn't work for me.
Any help?
The problem is EF can't translate the null-coalescing operator to SQL. Personally I don't see what's wrong with checking the result with an if statement before executing the next query. However, if you don't want to do that, then because your result is always going to be a single query why not do something like:
var wsdetails = (from assetTable in Repository.Asset
join userAsset in Repository.UserAsset on
assetTable.Asset_Id equals userAsset.Asset_Id
join subLocationTable in Repository.SubLocation on
assetTable.Sub_Location_Id equals subLocationTable.Sub_Location_ID
where userAsset.User_Id == userCode
&& assetTable.Asset_TypeId == 1 && assetTable.Asset_SubType_Id == 1
select new { workstation = subLocationTable.Sub_Location_Name, location = assetTable.Location_Id }).FirstOrDefault();
result = (from emp in this.Repository.Employee
join designation in this.Repository.Designation on
emp.DesignationId equals designation.Id
where emp.Code == userCode
select new EmployeeDetails
{
firstname = emp.FirstName,
lastname = emp.LastName,
designation = designation.Title
}).SingleOrDefault();
result.LocationId = wsdetails != null ? wsdetails.location : "someDefaultValue";
result.WorkStationName = wsdetails != null ? wsdetails.workstation ?? "someDefaultValue";
Instead of the "binary" operator ?? maybe you should use the good old ternary one, ? :, like in
wsdetails != null ? wsdetails.location : null
Try not evaluating the first query, and use it in the second query. This should result in a single SQL statement.
var wsdetails = (from assetTable in Repository.Asset
join userAsset in Repository.UserAsset on
assetTable.Asset_Id equals userAsset.Asset_Id
join subLocationTable in Repository.SubLocation on
assetTable.Sub_Location_Id equals subLocationTable.Sub_Location_ID
where userAsset.User_Id == userCode
&& assetTable.Asset_TypeId == 1 && assetTable.Asset_SubType_Id == 1
select new { workstation = subLocationTable.Sub_Location_Name, location = assetTable.Location_Id });
// wsdetails is still an IEnumerable/IQueryable
result = (from emp in this.Repository.Employee
join designation in this.Repository.Designation on
emp.DesignationId equals designation.Id
where emp.Code == userCode
select new EmployeeDetails
{
firstname = emp.FirstName,
lastname = emp.LastName,
designation = designation.Title,
LocationId = wsdetails.First().location,
WorkStationName = wsdetails.First().workstation
}).SingleOrDefault();