I'm struggling with a conversion of SQL query to LINQ.
Here is the SQL:
SELECT dbo.ORGANIZATION.ORGANIZATION_ID,
dbo.ORGANIZATION.ORGANIZATION_NAME,
dbo.PWR_ORGANIZATION_DIRECTORY.DIRECTORY_IDENTIFIER,
dbo.DETAIL_REQUIREMENT.DETAIL_ID,
dbo.DETAIL_REQUIREMENT.DETAIL_IDENTIFIER,
dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.DIRECTORY_ATTRIBUTE,
dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.ATTRIBUTE_VALIDATION,
dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.ATTRIBUTE_TRANSFORMATION,
dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.DETAIL_ACCESS
FROM dbo.ORGANIZATION INNER JOIN
dbo.DETAIL_REQUIREMENT ON dbo.ORGANIZATION.ORGANIZATION_ID = dbo.DETAIL_REQUIREMENT.ORGANIZATION_ID INNER JOIN
dbo.PWR_ORGANIZATION_DIRECTORY INNER JOIN
dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING ON dbo.PWR_ORGANIZATION_DIRECTORY.ORGANIZATION_ID = dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.ORGANIZATION_ID AND
dbo.PWR_ORGANIZATION_DIRECTORY.DIRECTORY_TYPE_ID = dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.DIRECTORY_TYPE_ID AND
dbo.PWR_ORGANIZATION_DIRECTORY.DIRECTORY_ID = dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.DIRECTORY_ID ON
dbo.DETAIL_REQUIREMENT.DETAIL_ID = dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.DETAIL_ID AND
dbo.ORGANIZATION.ORGANIZATION_ID = dbo.PWR_ORGANIZATION_DIRECTORY_MAPPING.ORGANIZATION_ID
WHERE dbo.ORGANIZATION.ORGANIZATION_ID = 0 AND
dbo.PWR_ORGANIZATION_DIRECTORY.DIRECTORY_ID = 1 AND
dbo.PWR_ORGANIZATION_DIRECTORY.DIRECTORY_TYPE_ID = 1
And this is how I started but got confused when there were two and three joins between tables:
var megaFetch = from org in context.Organizations
join detReq in context.DetailRequirements on org.OrganizationId equals detReq.OrganizationId
join detMap in context.OrganizationDirectoryMappings on org.OrganizationId equals detMap.OrganizationId &&
Can someone guide me here?
Thanks.
If you need to join a tables in more than one column, create anonymous types with both sides having same number of fields. It should be like;
new {col1 = x.col1, col2 = x.col2, ...} equals new { col1 = y.col1, col2 = y.col2, ...}
Related
I have the following SQL request for a report.
select customers."AppId", second_dep "SecondDeps", first_dep "FirstDeps",
customers_count "Customers", registrations "Registrations"
From (select Count("AppId") as customers_count, "AppId"
FROM "Customers"
join "Advertisers" A on "Customers"."AdvertiserId" = A."AdvertiserId"
join "Categories" C2 on "Customers"."CategoryId" = C2."CategoryId"
where A."Name" in (:AdvertiserNames)
AND C2."Name" = :CategoryName
GROUP BY "AppId"
) as customers
left join
(select C."AppId", count(CE.*) as second_dep
from "CustomerEvents" as CE
inner join "Customers" C on CE."CustomerId" = C."CustomerId"
WHERE "EventType" = 'deposit'
and "Again" = TRUE
GROUP BY C."AppId") as dep2 on customers."AppId" = dep2."AppId"
left join
(select C."AppId", count(CE.*) as first_dep
from "CustomerEvents" as CE
inner join "Customers" C on CE."CustomerId" = C."CustomerId"
WHERE "EventType" = 'deposit'
and "Again" = false
GROUP BY C."AppId") as dep on customers."AppId" = dep."AppId"
left join
(select C."AppId", count(CE.*) as registrations
from "CustomerEvents" as CE
inner join "Customers" C on CE."CustomerId" = C."CustomerId"
WHERE "EventType" = 'registration'
GROUP BY C."AppId") as regs on regs."AppId" = customers."AppId";
The string with problem is
where A."Name" in (:AdvertiserNames)
I would like to skip it if AdvertiserNames is empty. Is it possible? Ok, I can check it on the code side, but this way will leads me to copy whole request with some small difference (I mean if AdvertiserNames is empty run SQL without where A."Name" in (:AdvertiserNames)). Or I can use concatenation to get suitable SQL. I dont like this way too.
About my technology stack. It's .NET Core 2.2 with PostgreSQL. Here is the code of whole report method:
public IQueryable<ByApplicationsReportModel> ByApplications(string category, List<string> advertisers)
{
var rawSql = new RawSqlString(#"
select customers.""AppId"", second_dep ""SecondDeps"", first_dep ""FirstDeps"",
customers_count ""Customers"", registrations ""Registrations""
From (select Count(""AppId"") as customers_count, ""AppId""
FROM ""Customers""
join ""Advertisers"" A on ""Customers"".""AdvertiserId"" = A.""AdvertiserId""
join ""Categories"" C2 on ""Customers"".""CategoryId"" = C2.""CategoryId""
where A.""Name"" in (#AdvertiserNames)
AND C2.""Name"" = #CategoryName
GROUP BY ""AppId""
) as customers
left join
(select C.""AppId"", count(CE.*) as second_dep
from ""CustomerEvents"" as CE
inner join ""Customers"" C on CE.""CustomerId"" = C.""CustomerId""
WHERE ""EventType"" = 'deposit'
and ""Again"" = TRUE
GROUP BY C.""AppId"") as dep2 on customers.""AppId"" = dep2.""AppId""
left join
(select C.""AppId"", count(CE.*) as first_dep
from ""CustomerEvents"" as CE
inner join ""Customers"" C on CE.""CustomerId"" = C.""CustomerId""
WHERE ""EventType"" = 'deposit'
and ""Again"" = false
GROUP BY C.""AppId"") as dep on customers.""AppId"" = dep.""AppId""
left join
(select C.""AppId"", count(CE.*) as registrations
from ""CustomerEvents"" as CE
inner join ""Customers"" C on CE.""CustomerId"" = C.""CustomerId""
WHERE ""EventType"" = 'registration'
GROUP BY C.""AppId"") as regs on regs.""AppId"" = customers.""AppId""");
var advertisersParam = new NpgsqlParameter("AdvertiserNames",
string.Join(",", advertisers) );
var categoryParam = new NpgsqlParameter("CategoryName", category);
return _context.ByApplicationsReportModels
.FromSql(rawSql, categoryParam, advertisersParam);
}
Any ideas?
You might try changing where A.""Name"" in (#AdvertiserNames) to where (A.""Name"" in (#AdvertiserNames) or #AdvertiserNames = '').
Instead of concatenating your advertisers into a string, you could just pass an array of strings directly to your query:
var advertisersParam = new NpgsqlParameter("AdvertiserNames", advertisers));
In SQL, instead of using the x IN (#advertisers) construct, you would need to change to x = ANY (#advertisers).
Note: you would still need an additional clause if you want the check to pass when #advertisers is empty.
I have this rather complex query in SQL server 2008:
declare #LanguageID as int = 1
select k.datePublish, k.dateEditing, k.dateTables
from TableAreasLevel1 as areaL1
inner join TableAreasLevel2 as areaL2
on areaL1.LanguageID = areaL2.LanguageID and
areaL1.CodeAreaLevel1 = areaL2.CodeAreaLevel1
inner join TableAreasLink as link
on areaL2.CodeAreaLevel1 = link.CodeAreaLevel1 and
areaL2.CodeAreaLevel2 = link.CodeAreaLevel2 and
inner join TableProducts as tblProds
on tblProds.CodeAreaLevel1 = areaL1.CodeAreaLevel1 and
tblProds.CodeAreaLevel2 = areaL2.CodeAreaLevel2
inner join TableSI_Products as prod
on prod.SiAreaCode = link.SiAreaCode
inner join TableCalendar as k
on k.KodTableSI_Products = tblProds.KodTableSI_Products
where areaL1.LanguageID = #LanguageID and
prod.Code = 'some string' and
k.LanguageID = #LanguageID and
tblProds.LanguageID = #LanguageID;
I am trying to develop the same query in LINQ, but I get error when I try join the table TableProducts, i.e the third consecutive join.
Here is my LINQ query:
List<Tuple<DateTime, DateTime, DateTime>> dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
new { areaL2.CodeAreaLevel1, areaL2.LanguageID }
join link in gpe.TableAreasLink
on new { areaL2.CodeAreaLevel1, areaL2.CodeAreaLevel2, areaL2.RbrOblastNivo2} equals
new {link.CodeAreaLevel1, link.CodeAreaLevel2}
join tblProds in gpe.TableProducts
on tblProds. // The name tblProds is not in the scope of the left side of 'equals'
);
Is the problem connected with how the tables are designed or, something else I should check for?
Any ideas, why tblProds is not visible in the scope of the LINQ query?
You are using Query as your guide something like:
on k.KodTableSI_Products = tblProds.KodTableSI_Products
but take a look at your linq:
on new { areaL1.CodeAreaLevel1, areaL1.LanguageID } equals
it has two fields. I think its not a good idea.
linq join something like
var dates = (from areaL1 in gpe.TableAreasLevel1
join areaL2 in gpe.TableAreasLevel2
on areaL1.PKFields equals areaL2.PKFields
where areaL1.CodeAreaLevel1== areaL2.CodeAreaLevel1 && areaL1.LanguageID = areaL2.LanguageID
Select new YournewClass{YournewClass.Field1=areaL1.fields1, And so on}
)
You can do to join the other tables with aliases.
Sorry need to go for now.
I'm giving you an idea.
Hope it helps.
I have a problem. I get all data in var type variable and then want to apply a join with database table in code first approach. Facing problem, lot of search on internet and apply but failed.
var joinedData =
from menuGroup in _menuGroupMenusRepository.GetAll()
.Where(x => x.GroupId == input.GroupId)
join menus in _menuRepository.GetAll()
on menuGroup.MenuId equals menus.Id
join categSubcateg in _menuCategSubCategRepository.GetAll()
on menus.Id equals categSubcateg.MenuId
join categ in _menuCategoryRepository.GetAll()
on categSubcateg.CategoryId equals categ.Id
select new
{
CategoryId = categSubcateg.CategoryId,
CategoryName = categ.Category,
};
Now I want joinedData variable join with MainMenuSort table.
MainMenuSort table also have groupid and categoryid.
to perform join you just need to do as below
var q=(from jd in joinedData
join mms in dataContext.MainMenuSort
on jd.CategoryId equals mms.CategoryId
select jd).ToList();
if its datatable then
var q=(from jd in joinedData
join mms in dtMainMenuSort.AsEnumerable()
on jd.CategoryId equals mms.Field<int>("CategoryId")
select jd).ToList();
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 have a problem creating the following SQL Statement using LINQ & C#
select c.IDAddenda, c.Descripcion
from CatAddendas c
right join EmpresaAddenda e on e.IDAddenda = c.IDAddenda
where e.rfc = 'SUL010720JN8'
order by c.IDAddenda asc
I got this:
public IEnumerable<CatAddenda> TraeAddendas(string rfc)
{
DataClasses1DataContext dc = new DataClasses1DataContext(...);
return (from adds in dc.EmpresaAddendas
cats.IDAddenda into joined
where adds.RFC == rfc
select adds.CatAddenda);
}
This is not doing a right join, so any ideas?
var RightJoin = from adds in dc.EmpresaAddendas
join cats in CatAddendas
on adds.IDAddenda equals cats.IDAddenda into joined
from cats in joined.DefaultIfEmpty()
select new
{
Id = cats.IDAddenda,
Description = cats.Descripcion
};
var results = from e in EmpresaAddenda
join c in CatAddendas
on e.IDAddenda equals c.IDAddenda into f
from c in f.DefaultIfEmpty()
select new
{
ID = c.IDAddenda,
Description = c.Descripcion
};
You can apply where and order by on the results.