Left Join using Linq with condition - c#

I am trying to create a left join with a condition in my C# code. I can write it in SQL Server, but I am having problems writing it as a lambda expression. Here is a rough part of my SQL Code:
Select x.RequestId, aud.DepartmentId
From Requests x
Left Join UserDepartment ud on x.AssignedToTeam = ud.DepartmentId and ud.User = 'Joe'
I know how to write the Left Join but am unfamiliar with how or if it is possible to add the condition.

I suspect you want something like this:
var query = from request in db.Requests
join department in db.UserDepartments
.Where(dep => dep.User == "Joe")
on request.AssignedToTeam equals department.DepartmentId
into departments
from dep in departments.DefaultIfEmpty()
select new { request.RequestId,
DepartmentId = dep == null ? null : (int?) dep.DepartmentId
};
(Obviously change how you want to handle the absence of a department ID if necessary.)

Check out the MSDN article: How to: Perform Left Outer Joins (C# Programming Guide)

var request = db.View.Join(
db.UserDepartment.Where(w=>w.User=="Joe"),
a=>a.AssignedToTeam,
b=>b.DepartmentId,
(a,b)=> new {View = a, UserDepartment = b});

Related

Left join with where clause in linq

I am trying to do a left join with a where clause in linq.
I have leadsQuery table with 2500 rows. I want to join the LeadCons table into it. For a lead there can be multiple entries in the LeadCons table, hence I want to join only when the Status match. Else I want the fields to be NULL.
var data = from lead in leadsQuery
join lcs in context.LeadCons on lead.ID equals lcs.LeadId into leadsWithCons
from lcs in leadsWithCons.DefaultIfEmpty()
where lead.Status == lcs.Status
select new
{
LeadId = lead.ID,
Source = lead.Source.ToString(),
};
This query gives me ~1500 rows and leadsQuery has 2500. What am I doing wrong here?
A late answer, hoping it is still helpful:
First, you aren't selecting any values from LeadCons, so what is the purpose of a join?
I shall assume maybe you want to extend your select, so let us say you want to select the property foo, so my next question: Why do you need a left join in your case? You can simply do a select:
var data = from lead in leadsQuery
select new
{
Foo = context.LeadCons.Where(lcs => lead.Status == lcs.Status).SingleOrDefault().foo
LeadId = lead.ID,
Source = lead.Source.ToString(),
};
This way you have the same number of items and for each item the desired foo value.
Have you tried just changing the your join to a join with multiple conditions, and then removing the where 'status equal status'
from lead in leadsQuery
join lcs in context.LeadCons on new {
p1 = lead.ID,
p2 = lead.Status
}
equals
new {
p1 = lcs.LeadId,
p2 = lcs.Status
}
you can have a look at this nice article:
https://smehrozalam.wordpress.com/2010/04/13/linq-how-to-write-queries-with-complex-join-conditions/

getting error in joining dictionary with table

I want to have join query from a table with a dictionary based on a common field, my query is:
var query = from c in db.Exp
join d in lstUniprotDic on c.UniID equals d.Key
select new
{
c.UniID,
IdentityPercent=d.Value.ToString(),
c.PrId,
c.SpotNo
}
but i got the following error
Local sequence cannot be used in LINQ to SQL implementation of query operators except the Contains() operator.
That pretty much says it all. You can't use the dictionary in your LINQ to SQL query except when using Contains.
Solution:
(from c in db.Exp where lstUniprotDic.Keys.Contains(c.UniID) select c).AsEnumerable()
join d in lstUniprotDic on c.UniID equals d.Key
select new
{
c.UniID,
IdentityPercent=d.Value.ToString(),
c.PrId,
c.SpotNo
}
I am not sure if the usage of lstUniprotDic.Keys in the LINQ to SQL query is actually working.
If not, try using this code instead:
var ids = lstUniprotDic.Keys.ToArray();
(from c in db.Exp where ids.Contains(c.UniID) select c).AsEnumerable()
join d in lstUniprotDic on c.UniID equals d.Key
select new
{
c.UniID,
IdentityPercent=d.Value.ToString(),
c.PrId,
c.SpotNo
}

Multiple table linq query?

Could you help me translate this SQL query in Linq and Lambda expression.
SELECT * FROM User
JOIN UserIdentifier ON User.id = UserIdentifier.user_fk
JOIN UserPassword ON User.id = UserPassword.user_fk
WHERE UserIdentifier.identifier_value = "key" AND UserPassword.password = "1234"
I already wrote this
var query = from u in context.Users
join ui in context.UserIdentifiers on u.id equals ui.user_fk into Joined
from j in Joined.DefaultIfEmpty()
join up in context.UserPasswords on u.id equals up.user_fk into Joined2
from ???
select new { id = u.id, identifier = j.identifier_value, password = Joined2.???}
with help of http://paragy.wordpress.com/2010/11/18/multiple-joins-with-linq-and-lambda/
I'm not a happy user of linq. Actually I don't like linq because of this kind of request. This one is simple but when you try complex request linq is a nightmare. It's even worst with dynamic request. I always have problem with linq syntax and the web doesn't really help. I don't find a correct documentation to write queries.
I guess I'm not the first one to ask this question but all the documentation I found seems wrong or doesn't help me. This is a simple query and I don't find correct help. I'm still waiting someone prove me that link is not just another POC.
You're missing a where clause.
And your SQL joins are regular INNER JOINs, so you don't need these join ... into g from x in g.DefaultIfEmpty() -> that's how you do an equivalent of LEFT OUTER JOIN.
var query = from u in context.Users
join ui in context.UserIdentifiers on u.id equals ui.user_fk
join up in context.UserPasswords on u.id equals up.user_fk
where ui.identifier_value == "key" && up.password == "1234"
select new
{
id = u.id,
identifier = ui.identifier_value,
password = up.password
};

Why do I have do assign subquery to a variable outside of my main query

In the GetTransfers() method below I have to assign the result of GetAllocations() to a variable outside of my main query otherwise the query fails. Why do I have to do that? Is there a better way?
When the query fails I get this error:
{System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[XCBusinessLogic.Presentation.Allocation] GetAllocations()' method, and this method cannot be translated into a store expression.
This query works:
public IQueryable<Transfer> GetTransfers()
{
IQueryable<Allocation> wxyz = GetAllocations();
IQueryable<Transfer> query =
from transfer in Context.XC_TRANSFERS
//let wxyz = GetAllocations()
join trader in Context.MGRS on transfer.TRADER_ID equals trader.MGR_NO
join ssm in Context.SSM_CORES on transfer.SSM_ID equals ssm.SSM_ID
join desk in Context.XC_DESKS on transfer.DESK_ID equals desk.DESK_ID
select new Transfer
{
// snip
_AllocationList = wxyz.Where(x => x.TRANSFER_ID == transfer.TRANSFER_ID)
};
return query;
}
This query fails:
public IQueryable<Transfer> GetTransfers()
{
//IQueryable<Allocation> wxyz = GetAllocations();
IQueryable<Transfer> query =
from transfer in Context.XC_TRANSFERS
let wxyz = GetAllocations()
join trader in Context.MGRS on transfer.TRADER_ID equals trader.MGR_NO
join ssm in Context.SSM_CORES on transfer.SSM_ID equals ssm.SSM_ID
join desk in Context.XC_DESKS on transfer.DESK_ID equals desk.DESK_ID
select new Transfer
{
// snip
_AllocationList = wxyz.Where(x => x.TRANSFER_ID == transfer.TRANSFER_ID)
};
return query;
}
This query fails:
public IQueryable<Transfer> GetTransfers()
{
//IQueryable<Allocation> wxyz = GetAllocations();
IQueryable<Transfer> query =
from transfer in Context.XC_TRANSFERS
//let wxyz = GetAllocations()
join trader in Context.MGRS on transfer.TRADER_ID equals trader.MGR_NO
join ssm in Context.SSM_CORES on transfer.SSM_ID equals ssm.SSM_ID
join desk in Context.XC_DESKS on transfer.DESK_ID equals desk.DESK_ID
select new Transfer
{
// snip
_AllocationList = GetAllocations().Where(x => x.TRANSFER_ID == transfer.TRANSFER_ID)
};
return query;
}
GetAllocations Method:
public IQueryable<Allocation> GetAllocations()
{
IQueryable<Allocation> query =
from alloc in Context.XC_ALLOCATIONS
join acm in Context.ACMS on alloc.ACCT_NO equals acm.ACCT_NO
join b in Context.BUM_DETAILS.Where(x => x.FIRM_NO == 1 && x.CATEGORY_ID == 1937) on acm.ACCT_NO equals b.ACCT_NO into bumDetails
from bumDetail in bumDetails.DefaultIfEmpty()
where acm.FIRM_NO == 1
select new Allocation
{
AccountName = acm.ACCT_NAME
// snip
};
return query;
}
Linq to Entities translate everything in the query from transfer in Context.XC_TRANSFERS ... into SQL. So the only expressions that are allowed inside that query are ones that can easily be translated to SQL.
Linq to Entities cannot figure out how a .NET method like GetAllocations() works. How should it do that? There could be any form of crazy code inside a method. How could it turn that into SQL?
In your case the method actually contains another Linq to Entities query. Maybe you could copy-paste one query into the interior of the other. But I don't think that would improve your code!
So just keep the working solution you have.
You can get around the problem by using join with your method followed by an into
IQueryable<Transfer> query =
from transfer in Context.XC_TRANSFERS
join allocation in GetAllocations() on transfer.TRANSFER_ID equals allocation.TRANSFER_ID into allocationList
join trader in Context.MGRS on transfer.TRADER_ID equals trader.MGR_NO
join ssm in Context.SSM_CORES on transfer.SSM_ID equals ssm.SSM_ID
join desk in Context.XC_DESKS on transfer.DESK_ID equals desk.DESK_ID
select new Transfer
{
// snip
_AllocationList = allocationList
};
I was having a very similar issue and the answer from Aducci did it for me. This was what I was trying to do:
query = from x in query
where GetServicesQuery(db, options).Any(service => /*my criteria*/)
select x;
It was resolved by doing this as Aducci suggested:
query = from x in query
join service in GetServicesQuery(db, localOptions) on x.ID equals service.ID into services
where services.Any(service => /*my criteria*/)
select x;
I am posting this solution because my case was different from above (needing the subquery in the where not the select). If anyone ever stumbles onto this thread with the same issue as me, hopefully this will save them some searching around.
This one was stressing me out since GetServicesQuery has a lot of criteria that I don't want to keep repeating.

linq - how combine conditions in a join statement

im working with xml and linq.
I have 2 xml files both contain "ID" and "LANGUAGE"
I want to do a join based on where the both the ID and LANGUAGE are equal in both files
I have something like this:
var data=
from details in h_details.Descendants("ROW")
join inst in instance.XPathSelectElements("//Row")
on details.Element("ID").Value
equals inst.XPathSelectElement("Field[#Name=\'h_id\']").Value
and on details.Element("LANGUAGE").Value
equals inst.XPathSelectElement("Field[#Name=\'h_lang\']").Value
basically the "and" statement wont work, so how do i join based on 2 conditions?
Anonymous types to the rescue.
var data=
from details in h_details.Descendants("ROW")
join inst in instance.XPathSelectElements("//Row")
on new {
x = details.Element("ID").Value,
y = details.Element("LANGUAGE").Value
} equals new {
x = inst.XPathSelectElement("Field[#Name=\'h_id\']").Value,
y = inst.XPathSelectElement("Field[#Name=\'h_lang\']").Value
}
select ... ;
try union to get the both lists and join them

Categories

Resources