I have a linq query w/ entity frameworks that works and gets the needed information, but now i am having trouble doing the opposite.
Currently it gets all the data that is needed using the joins to link tables but i need to to get some data that is not match some of the joins.
I know you can only use "equals" om linq, but i need info that is not equals
i.e. join ec in c.IsoNe on ap.idLook not equals ec.idAll
Below is the working code, but not how i need it now. any help would be appreciated...
var test = (from bil in bilats
join ap in c.Allegro on bil.idAll equals ap.idAll
join ec in c.IsoNe on ap.idLook equals ec.idAll
join cb in c.Comp on ap.idCompBuy equals cb.idComp
join cs in c.Com on ap.idCompSell equals cs.idComp
join iby in c.IsoNe on cb.idComp equals iby.idComp
join iss in c.IsoNe on cs.idComp equals isl.idComp
orderby bil.HBegin ascending
where bil.HBegin >= ec.DateTStart
where bil.HBegin < ec.DateTEnd
select new
{
Cont = ec.ContractID,
ContType = ap.idScheduleType,
Sel = isel.ISONE1,
Buy = ibel.ISONE,
HBegin = bil.HBegin,
}).ToList();
As far as I know, you'll have to create a Cartesian product and then use a where-condition to filter it. (I'm making the perhaps rash assumption that you want an inner join rather than a left join, but an inner join is what the join keyword represents.) Something like this:
var test = (from bil in bilats
join ap in c.Allegro on bil.idAll equals ap.idAll
from ec in c.IsoNe where ap.idLook != ec.idAll
join cb in c.Comp on ap.idCompBuy equals cb.idComp
join cs in c.Com on ap.idCompSell equals cs.idComp
join iby in c.IsoNe on cb.idComp equals iby.idComp
join iss in c.IsoNe on cs.idComp equals isl.idComp
orderby bil.HBegin ascending
where bil.HBegin >= ec.DateTStart
where bil.HBegin < ec.DateTEnd
select new
{
Cont = ec.ContractID,
ContType = ap.idScheduleType,
Sel = isel.ISONE1,
Buy = ibel.ISONE,
HBegin = bil.HBegin,
}).ToList();
Sounds like a join might be the wrong approach. Have a look at unions or subqueries
C# linq union question
how to do subquery in LINQ
Related
I am not trying to join my table using left outer join in LINQ where one of my join conditions does not satisfy. How can I still get the default record in my dataset? My SQL query runs perfectly fine but my join query is not returning the data.
Below is my SQL query where my left outer join works fine:
select
w.issueid as Issue
from worklog w
join jiraissue as j on w.issueid=j.ID
join issuetype AS ty ON ty.ID = j.issuetype
join project AS p on p.ID=j.PROJECT
left outer join customfieldvalue cfv on cfv.ISSUE = w.issueid
Below is my LINQ query in C# where if cfv.issue in the last join is not available in the table, I want to still return the default column.
var data = (from w in worklogs
join i in issuetypes on j.issuetype equals i.ID
join p in projects on j.PROJECT equals p.ID into table0
from c in table0.DefaultIfEmpty()
join cfv in customfieldvalues on w.issueid equals cfv.ISSUE into table1
from d in table1.DefaultIfEmpty()
{
IssueKey = l.Key.pkey + '-' + l.Key.issuenum,
Hours = l.Sum(w => w.timeworked)
}).ToList();
Any help is appreciated.
Thank you.
I'm sorry for telling that I've a little bit weak on LINQ, I always do write SQL query before I start working on the complicated LINQ.
I want to ask that how to convert this SQL Query into LINQ with LEFT JOIN with multiple ON conditons with the OR operator.,
m.MerchandiseId will be use for twice in ON condition
SELECT
*
FROM
Inbox AS i
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS m ON
u.MerchandiseId = m.MerchandiseId
OR
i.ToMerchantId = m.MerchandiseId
WHERE
i.ToCompanyId = 10
OR
i.FromCompanyId = 10
var message = (from i in db.Inbox
join u in db.User on i.FromUserId equals u.UserId
join m in db.Merchandise on u.MerchandiseId equals m.MerchandiseId //here I want to ON i.MerchantId = m.MerchandiseId, but it doesn't allow
where i.ToCompanyId == user.CompanyId || i.FromCompanyId == user.CompanyId
orderby i.CreatedAt descending
group m.MerchandiseId by new { m.MerchandiseId, m.MerchandiseName } into grp
select new
{
MerchandiseId = grp.Key.MerchandiseId,
MerchandiseName = grp.Key.MerchandiseName,
InboxMessage = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.InboxMessage).FirstOrDefault(),
CreatedAt = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.CreatedAt).FirstOrDefault(),
}).ToList();
The bottom LINQ Query I've write for it. However, I just can work on the left join with multiple ON clause in LINQ. Appreciate if someone would help me on this. Thanks!
I don't believe Linq supports the use of the OR operator with multiple columns, but that said, I wouldn't use OR even in SQL as it makes the join's intention unclear and it also obscures where the data originated from - it also isn't immediately clear what happens if there are multiple matches for each column. Instead I would JOIN twice on the different columns and let the projection-clause handle it:
SELECT
*
FROM
Inbox
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS userMerchant ON u.MerchandiseId = userMerchant.MerchandiseId
LEFT OUTER JOIN Merchandise AS inboxMerchant ON Inbox.ToMerchantId = inboxMerchant .MerchandizeId
WHERE
Inbox.ToCompanyId = 10
OR
Inbox.FromCompanyId = 10
This can then be translated into Linq using the LEFT OUTER JOIN approach ( How to implement left join in JOIN Extension method )
Note that if you're using Entity Framework then you don't need to worry about doing any of this at all! Just use Include:
var query = db.Inbox
.Include( i => i.User )
.Include( i => i.User.Merchandise )
.Include i => i.Merchandise )
.Where( i => i.ToCompanyId = 10 || i.FromCompanyId == 10 );
I have this query
SELECT t.NomeTipo, sum(v.QtdProduto)
FROM [dbo].[Vendas] AS V
RIGHT JOIN [dbo].[Produtos] AS P ON V.IdProduto = P.IdProduto
INNER JOIN [dbo].[Tipos] AS T ON P.IdTipo = T.IdTipo
group by t.NomeTipo
order by t.NomeTipo
I have tried this
var queryTipos = from vendas in repositorioVendas.Vendas
join produtos in repositorioProduto.Produtos.DefaultIfEmpty()
on vendas.IdProduto equals produtos.IdProduto
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by new { tipos.NomeTipo, vendas.QtdProduto }
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key.NomeTipo,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
With this query I got only two results, but when I run straight from the database I get something like this:
Bebidas 16
Bolos 14
Frios 16
Pães 21
The trick is to realize that you can rewrite your query with a left join instead of a right join by swapping the order of the first two tables and that Linq doesn't have a way to really handle right joins. Also you're grouping was wrong.
var queryTipos = from produtos in repositorioProduto.Produtos
join vendas_pj in repositorioVendas.Vendas
on vendas_pj.IdProduto equals produtos.IdProduto into joined
from vendas in joined.DefaultIfEmpty()
join tipos in repositorioTipo.Tipos
on produtos.IdTipo equals tipos.IdTipo
group vendas by tipos.NomeTipo
into novoGrupo
select new
{
NomeTipo = novoGrupo.Key,
QtdProduto = novoGrupo.Sum(x => x.QtdProduto)
};
Basically a Left join in SQL
From TableA
Left Join TableB
On TableA.ID = TableB.ID
is done in Linq like this
from a in repo.TableA
join b_pj in repo.TableB
on a.ID equals b_pj.ID into joined
from b in joined.DefaultIfEmpty()
I am using LinqToDB to help query a SQLite Database, however, I am having an issue where I need to do a join in a collection of joins. Here is what I have so far.
var craftList = from c in db.GetTable<Craft>()
join cP in db.GetTable<CraftProduct>() on c.ID equals cP.CraftID into cPS
join cM in db.GetTable<CraftMaterial>() on c.ID equals cM.CraftID into cMS
select new
{
Craft = c,
CraftProducts = cPS,
CraftMaterials = cMS
};
I need to do add to the groups cPS & cMS and have each element join with another table. Here is an example query that kind of shows you what needs to be done with the elements in cMS.
var materialList = from cM in db.GetTable<CraftMaterial>()
join i in db.GetTable<Item>() on cM.ItemID equals i.ID
select CraftMaterial.Build(cM, i);
I was able to figure out what I needed to do after some messing around, I just needed to do multiple queries.
var craftList = from craft in db.GetTable<Craft>()
join craftProduct in db.GetTable<CraftProduct>() on craft.ID equals craftProduct.CraftID into
craftProducts
join craftMaterial in db.GetTable<CraftMaterial>() on craft.ID equals craftMaterial.CraftID into
craftMaterials
select new
{
Craft = craft,
CraftProducts = from craftProduct in craftProducts
join item in db.GetTable<Item>() on craftProduct.ItemID equals item.ID
select CraftProduct.Build(craftProduct, item),
CraftMaterials = from craftMaterial in craftMaterials
join item in db.GetTable<Item>() on craftMaterial.ItemID equals item.ID
select CraftMaterial.Build(craftMaterial, item)
};
I have 2 inner joins (3 tables) but I don't know and I find it hard to implement my research about outer join in LINQ. How do I change the last inner join to outer join, such that column will still join even if the column (Role) is null?
Here's an existing SQL version of this which I want to convert to LINQ:
SELECT dbo.EmployeeAccess.id, dbo.EmployeeAccess.EmpNo, dbo.EmployeeAccess.RoleID, dbo.EmployeeAccess.Active, dbo.EmployeeAccessLevel.Role,
dbo.View_HCM.LNameByFName
FROM dbo.EmployeeAccess LEFT OUTER JOIN
dbo.EmployeeAccessLevel ON dbo.EmployeeAccess.RoleID = dbo.EmployeeAccessLevel.id INNER JOIN
dbo.View_HCM ON dbo.EmployeeAccess.EmpNo = dbo.View_HCM.EmpNo
LINQ I now have with 2 inner joins:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
}
Linq's outer join syntax uses 2 parts. First an into then DefaultIfEmpty
In your case, an outer join might look like this:
(from ea in context.EmployeeAccesses
join vh in context.View_HCM on (Int16)ea.EmpNo equals vh.EmpNo
join rl in context.EmployeeAccessLevels on ea.RoleID equals rl.id into outer_join
from subjoin in outer_join.DefaultIfEmpty()
select new EmployeeWithEmail{
EmpNum = ea.EmpNo ?? 0,
EmailAddress = vh.EmailAddress,
LNameByFname = vh.LNameByFName,
Active2 = ea.Active ?? false
}).ToList();
There are many tutorials on how to create the outer join in LINQ.