Why the following query results in an exception? - c#

The following query results in the exception:
"Unable to cast object of type 'System.Linq.Expressions.TypedConstantExpression' to type 'SD.LLBLGen.Pro.LinqSupportClasses.ExpressionClasses.SetExpression'.".
What could be the problem?
return (from ubt in meta.TableUbt
join tc in meta.TableTc on ubt.TCId equals tc.Id
where ubt.Ar110aid == ar110AId && tc.IsPayment
group ubt by new { ubt.Ar110aid, ubt.TCId } into tempTrans
join pyd in meta.TablePyd on tempTrans.Key.Ar110aid equals pyd.Ar110Aid
join pm in meta.TablePm on pyd.Ar110Id equals pm.Id
join tly in TableTly on new { pyd.TyId, ChrgTransId = tempTrans.Key.TCId }
equals new { tly.TyId, tly.ChrgTransId }
join cr in meta.TableCr on
new
{
TyId = (int?)pyd.TyId,
TxLevId = (int?)tly.TxLevId,
Ar101Id = (int?)pm.Ar101Id
}
equals
new
{
cr.TyId,
cr.TxLevId,
cr.Ar101Id
}
join crd in meta.TableCrd on cr.Id equals crd.TableCrId
where crd.StartingLimit <= tempTrans.Sum(b => b.Amount) &&
tempTrans.Sum(b => b.Amount) <= crd.EndingLimit
select crd.Id).FirstOrDefault();

Probably problem is in joining on TableTly. It seems to be local data set. and it's prohibited to join Db data and in-memory objects.

Related

Multiple Null Foreign keys group join error in Linq

I have this following LINQ statement which giving the following error
Type inference failed in the call to Group join
var EmployeeList = (from requestemployee in _context.BulkTransportRequestEmployees
join request in _context.BulkTransportRequests on requestemployee.BulkRequestBulkRequestId equals request.BulkRequestId
join employee in _context.Employees on requestemployee.EmployeeEmployeeId equals employee.EmployeeId
join deptemp in _context.EmployeeDepartments on employee.EmployeeId equals deptemp.EmployeeEmployeeId
join dept in _context.Departments on deptemp.DepartmentDepartmentId equals dept.DepartmentId
//Error is in here
join routepath in _context.RootPaths on new { Key1 = requestemployee.CityCityId, Key2 = requestemployee.RootRootId } equals new { Key1 = routepath.CityId, Key2 = routepath.RootId } into join_routepath
from routepath in join_routepath.DefaultIfEmpty()
join route in _context.Roots on routepath.RootId equals route.RootId
join destination in _context.Cities on routepath.CityId equals destination.CityId
join pass in _context.TransportPasses on employee.EmployeeId equals pass.IssuedToEmployeeId into join_employee_pass
from pass in join_employee_pass.DefaultIfEmpty()
where deptemp.IsDefaultDepartment == true &&
request.RequestType == 1 &&
employee.EmployeeType == emptype &&
DbFunctions.TruncateTime(request.TripDateAndTime) >= DbFunctions.TruncateTime(FromDate) &&
DbFunctions.TruncateTime(request.TripDateAndTime) <= DbFunctions.TruncateTime(ToDate) &&
(pass.IsHold == true || pass.IsCanceled == true || pass.IssuedDate == null || pass.PassType == 1)
group new { employee, request, routepath } by new
{
dept.DepartmentName,
employee.EmployeeId,
employee.EmpCode,
employee.EmployeeCallingName,
employee.EmployeeSurname,
employee.NameWithInitials
} into g
select new
{
g.Key.EmployeeId,
g.Key.EmpCode,
Employee = g.Key.EmployeeCallingName + " - " + g.Key.NameWithInitials,
g.Key.DepartmentName
}).ToList();
requestemployee keys are nullable types. So how could I establish this group join without error?
I figured it out. Just write down for others' use.
because requestemployee.CityCityIdandrequestemployee.RootRootId keys are nullable I need to change routepath.CityId and routepath.RootId also to accept null as follow
join routepath in _context.RootPaths on new { Key1 = requestemployee.CityCityId, Key2 = requestemployee.RootRootId } equals new { Key1 = (int?)routepath.CityId, Key2 = (int?)routepath.RootId } into join_routepath
from routepath in join_routepath.DefaultIfEmpty()

How to create LINQ from complex SQL?

I've this SQL query:
SELECT D.ID
FROM Documents AS D
INNER JOIN DocClasses AS DC WITH (NOLOCK)
ON D.DocClass = DC.ID
INNER JOIN DocSubClasses AS DSC WITH (NOLOCK)
ON D.DocSubClass = DSC.ID AND DSC.DocClassID = DC.ID
INNER JOIN DocPathFolders AS F WITH (NOLOCK)
ON D.DocPathFolderID = F.ID
WHERE
DC.ShortName = 'PAY' AND DSC.Name = 'xxxxx'
AND UPPER(F.Description) = 'READY TO SEND'
I'm trying to convert this query into LINQ. Here is what I've done so far:
from D in ctx.Documents
join DC in ctx.DocClasses on D.DocClass equals DC.ID
join DSC in ctx.DocSubClasses
on new { D.DocSubClass, DSC.DocClassID } equals new { DSC.ID, DC.ID }
join F in ctx.DocPathFolders
on D.DocPathFolderID equals F.ID
where
DC.ShortName == "PAY"
&& DSC.Name == "xxxxx"
&& (F.Description).ToUpper() == "READY TO SEND"
select D.ID;
I'm getting error in this line:
join DSC in ctx.DocSubClasses on new { D.DocSubClass, DSC.DocClassID } equals new { DSC.ID, DC.ID }
Here, I'm getting following error:
The name 'DSC' is not in scope on the left side of 'equals'
The name 'DC' is not in scope on the right side of 'equals'
I'm new in LINQ and that's why I can't solve these error. I would apperciate any suggestion on the above. Thanks.
You should rearrange the properties in the anonymous objects like this:
join DSC in ctx.DocSubClasses
on new { D.DocSubClass, DC.ID } equals new { DSC.DocClassID, DSC.ID }
Those on the right should be of the table you are joining (DSC) and those on the left can be of previous tables
You can try with Lambda Join instead of using LINQ.
Your JOIN statements look like below in Lambda.
C# Fiddle
var result = ctx.Documents.Join(ctx.DocClasses , d => new { Id = d.DocClass }, dc => new { Id = dc.ID }, (d, dc) => new { doc = d, docClass = dc }) //INNER JOIN DocClasses
.Join(ctx.DocSubClasses , d => new { sc = d.doc.DocSubClass, Id = d.docClass.ID }, dsc => new { sc = dsc.ID, Id = dsc.DocClassID }, (d, dsc) => new { doc = d, dsc = dsc } ) //INNER JOIN DocSubClasses
.Join(ctx.DocPathFolders, d => new { fId = d.doc.doc.DocPathFolderID }, f => new { fId = f.ID }, (d, f) => new { doc = d, f = f }) //INNER JOIN DocPathFolders
.Where(x => x.doc.doc.docClass.ShortName == "PAY" && x.doc.dsc.Name == "xxxxx" && x.f.Description.ToUpper() == "READY TO SEND")//Apply where clause
.Select(y => y.doc.doc.doc.ID);//Select whatever you want
Here is how I've solved my issue:
from D in ctx.Documents
join DC in ctx.DocClasses on D.DocClass equals DC.ID
join DSC in ctx.DocSubClasses on new { D.DocSubClass, DC.ID } equals new { DocSubClass = DSC.ID, ID = DSC.DocClassID }
join F in ctx.DocPathFolders on D.DocPathFolderID equals F.ID
where DC.ShortName == "PAY" && DSC.Name == "xxxx" && (F.Description).ToUpper() == "READY TO SEND"
select D.ID;
Just switch DSC into right side of equals and DC to the left, and it should work fine.
join DSC in ctx.DocSubClasses on new { D.DocSubClass, DC.ID } equals new { DSC.ID, DSC.DocClassID}
Hint: Provided you have set your relations appropriately in your database you almost never need to use "join". It is easier to write in LINQ and relations are exposed as "navigational properties". You simply use "dot notation". ie:
var result = from d in ctx.Documents
where d.DocClasses.Any( dc => dc.ShortName == "PAY"
&& dc.DocSubClasses.Any( dsc => dsc.Name == "xxxxx" )
&& d.DocPathFolders.Any( dpf => dpf.Description.ToUpper() == "READY TO SEND" )
select d.ID;
Note: We don't have any idea on your model. I assumed the relations as 1-To-Many. If it were Many-To-1 then you would simply use notation like:
where d.DocClass.ShortName == "PAY"
&& d.DocClass.DocSubClass.Name == "xxxxx"
&& d.DocPathFolder.Description.ToUpper() == "READY TO SEND"
HINT2: Download and start using Linqpad from LinqPad.net. It is a great tool where you can not only test your LINQ queries but use as a .Net scratch pad.

T-SQL to LINQ query that has a case statement and a subquery in it

I'm a complete beginner in LINQ and I would like to convert this T-SQL query in LINQ
SELECT
CASE
WHEN D.IsBaseloadDefined = 1
THEN COUNT(D.DeviceID)
ELSE
(SELECT COUNT(DORG.DeviceID)
FROM DeviceOrganization DORG
INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
WHERE DORG.DeviceID = D.DeviceID
AND BL.RecursUntil >= GETDATE()
GROUP BY DORG.DeviceID)
END AS [Nb of devices]
FROM DeviceOrganization DO
INNER JOIN Device D ON DO.DeviceID = D.DeviceID
LEFT JOIN BaseloadDevice BD ON D.DeviceID = BD.DeviceID
LEFT JOIN Baseload B ON BD.BaseloadID = B.BaseloadID AND B.RecursUntil >= GETDATE()
INNER JOIN OrganizationHierarchy OH ON DO.OrganizationID = OH.SubOrganizationID
WHERE OH.OrganizationID = 6
AND D.IsActive = 1
group by D.DeviceID, D.IsBaseloadDefined
I've seen this topic but I don't really understand the answer
The only thing I could do so far is this, and now I'm completly lost
from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
group d.DeviceID by d.DeviceID).Count()
Instead of get count of group
group d.DeviceID by d.DeviceID).Count()
you should save result in variable
var data = from deviceO in _context.DeviceOrganizations
join d in _context.Devices on deviceO.DeviceID equals d.DeviceID
join bd in _context.BaseloadDevices on d.DeviceID equals bd.DeviceID
join b in _context.Baseloads on bd.BaseloadID equals b.BaseloadID
join oh in _context.OrganizationHierarchies on deviceO.OrganizationID equals oh.SubOrganizationID
where oh.OrganizationID == OrganizationId
where d.IsActive == true
where b.RecursUntil <= DateTime.Now
and then you should do something like this:
//group by 2 properties
var result = data.GroupBy(d => new { d.DeviceID, d.IsBaseloadDefined })
.Select(g =>
{
//for each group we get IsBaseloadDefined property
var IsBaseloadDefined = g.Key.IsBaseloadDefined;
if (IsBaseloadDefined == 1)
{
return g.Count();
}
else
{
// here another select that return count:
//(SELECT COUNT(DORG.DeviceID)
//FROM DeviceOrganization DORG
// INNER JOIN Organization ORG ON DORG.OrganizationID = ORG.OrganizationID
//INNER JOIN BaseloadOrganization BO ON ORG.BaseloadOrganizationId = BO.OrganizationID
//INNER JOIN Baseload BL ON BO.BaseloadID = BL.BaseloadID
//WHERE DORG.DeviceID = D.DeviceID
//AND BL.RecursUntil >= GETDATE()
//GROUP BY DORG.DeviceID)
//in this query you should return Count() of group
return 1; //return group.Count() instead 1
}
});
I hope this helps you

multiple join on conditions sql to linq

how can i change the sql below to a linq.
select distinct * from dbo.TbleA a
left outer join dbo.TbleB b on a.schid = b.schid
left outer join dbo.TbleC c on b.addrid=c.addrid
and c.userid=a.userid
where b.addrid=1
here is my linq version which is causing error:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)
i am getting error around here:
join c in db.TbleC on new { w = b.addrid, z = a.userid } equals new {
w=(int?)c.addrid, z=c.userid}
i do understand where the problem is i am comparing to two tables in my join.
thanks and the error is:
"the type of one of the expressions in the join clause is incorrect""Type inference failed in the call to join"
b.addrid - int,
a.userid - string,
c.addrid - int?
c.userid - string
We can't really tell what's wrong with your current query in terms of compilation without knowing the types involved, but it wouldn't be equivalent to your original SQL anyway, as you want left outer joins. I suspect you want something more like:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (int?)b?.addrid, z = a.userid }
equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where (b.addrid == 1)
That's if you can use C# 6 with the null conditional operator, of course. If not, you would at least logically need:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid into bs
from b in bs.DefaultIfEmpty()
join c in db.TbleC on new { w = (b == null ? default(int?) : (int?)b.addrid), z = a.userid }
equals new { w = c.addrid, z = c.userid } into cs
from c in cs.DefaultIfEmpty()
where b == null || b.addrid == 1
I suspect your error is caused by trying to compare anonymous classes within a LinQ statement which are not of the same type. I suggest you change the join to the following:
from a in db.TbleA
join b in db.TbleB on a.schid equals b.schid
join c in db.TbleC on new { w = (int?)b.addrid, z = a.userid } equals new { w=(int?)c.addrid, z=c.userid}
where (b.addrid == 1)

Linq With Entities List within Distinct List

I have a SQL Query that gets Distinct rows of Vendor Contacts, which is returning the proper number of rows:
SELECT DISTINCT v.VendorID, c.ContactID,
v.VendorName,
c.FirstName, c.MiddleName, c.LastName,
FROM VendorContacts vc
INNER JOIN Contact c
ON c.ContactID = vc.ContactID
INNER JOIN Vendor v
ON v.VendorID = vc.VendorID
LEFT JOIN [ContactServices] psvc
ON psvc.ContactID = c.ContactID
AND psvc.VendorID = v.VendorID
I have a method that I want to return of custom type, based on the above query:
public List<ProviderContactInfo> GetProviderContactInfo(ProviderContactInfo searchInfo)
{
using (var db = new MyContext())
{
var providerContactInfo =
(from vc in db.VendorContacts
join ps in db.ContactServices on new { vc.ContactID, vc.VendorID } equals new { ps.ContactID, ps.VendorID } into ps_join
from ps in ps_join.DefaultIfEmpty()
join c in db.Contacts on vc.ContactID equals c.ContactID
join v in db.Vendors on vc.VendorID equals v.VendorID
orderby vc.ContactID descending
select new ProviderContactInfo()
{
VendorName = v.VendorName,
FirstName = c.FirstName,
MiddleName = c.MiddleName,
LastName = c.LastName,
Services = (from o in db.ContactServices
join cps in db.Contacts on o.ContactID equals cps.ContactID
join vps in db.Vendors on o.VendorID equals vps.VendorID
join s in db.Services on o.ServiceID equals s.ServiceID
where ps.ServiceID == o.ServiceID
&& o.ContactID == c.ContactID
&& o.VendorID == v.VendorID
select s).ToList()
}).Distinct().ToList();
return providerContactInfo;
}
}
I'm getting the error:
Additional information: The 'Distinct' operation cannot be applied to
the collection ResultType of the specified argument.
Everything works fine when I remove the Services property from the new ProviderContactInfo so I'm sure it's in the way I'm trying to populate that property (which is of type List<Service>)
I know there are a lot of questions regarding Linq with Distinct etc but I couldn't find anything on this specific problem.
Please help!
EDIT This code works:
public List<ProviderContactInfo> GetProviderContactInfo(ProviderContactInfo searchInfo)
{
using (var db = new MyContext())
{
var providerContactInfo =
(from vc in db.VendorContacts
join c in db.Contacts on vc.ContactID equals c.ContactID
join v in db.Vendors on vc.VendorID equals v.VendorID
orderby vc.ContactID descending
select new ProviderContactInfo()
{
VendorName = v.VendorName,
FirstName = c.FirstName,
MiddleName = c.MiddleName,
LastName = c.LastName,
Services = (from o in db.ContactServices
join cps in db.Contacts on o.ContactID equals cps.ContactID
join vps in db.Vendors on o.VendorID equals vps.VendorID
join s in db.Services on o.ServiceID equals s.ServiceID
where o.ContactID == c.ContactID
&& o.VendorID == v.VendorID
select s).ToList()
}).Distinct().ToList();
return providerContactInfo;
}
}
You should add one more step to the process, to avoid applying Distinct() on the objects that have a collection (Services) property, the LINQ provider does not know how to handle it.
var providerContactInfo = from vc in db.VendorContacts
join ps in db.ContactServices on new { vc.ContactID, vc.VendorID } equals new { ps.ContactID, ps.VendorID } into ps_join
from ps in ps_join.DefaultIfEmpty()
join c in db.Contacts on vc.ContactID equals c.ContactID
join v in db.Vendors on vc.VendorID equals v.VendorID
orderby vc.ContactID descending
group ps by new
{
v.VendorName,
c.FirstName,
c.MiddleName,
c.LastName,
c.ContactID,
v.VendorID
} into g
select new ProviderContactInfo()
{
VendorName = g.Key.VendorName,
FirstName = g.Key.FirstName,
MiddleName = g.Key.MiddleName,
LastName = g.Key.LastName,
Services = (from e in g
from o in db.ContactServices
join cps in db.Contacts on o.ContactID equals cps.ContactID
join vps in db.Vendors on o.VendorID equals vps.VendorID
join s in db.Services on o.ServiceID equals s.ServiceID
where e.ServiceID == o.ServiceID
&& o.ContactID == g.Key.ContactID
&& o.VendorID == g.Key.VendorID
select s).ToList()
}
Wouldn't this be much simplier:
public IQueryable<VendorContact> GetProviderContactInfo(ProviderContactInfo searchInfo)
{
using (var db = new MyContext())
{
return providerContactInfo=db.VendorContacts
.Include(vc=>vc.Contacts)
.Include(vc=>vc.Services)
.Include(vc=>vc.Vendor)
.OrderByDescending(vc=>vc.ContactID);
}
}

Categories