Linq Group by and inner join - c#

I would like to replace this SQL command :
string dotazBankUcty = #"SELECT
H.UCET,
SUM(H.KON_STAV_MD) AS KON_STAV_MD,
SUM(H.KON_STAV_DAL) AS KON_STAV_DAL ,
SUM(H.KON_STAV_MD_MENA) AS KON_STAV_MD_MENA,
SUM(H.KON_STAV_DAL_MENA) AS KON_STAV_DAL_MENA,
MAX(UBUC.KOD_MENY) AS KOD_MENY
FROM UHLAVAKT H
inner join UBUC on H.UCET = UBUC.UCET GROUP BY H.UCET";
with a LINQ command. I tried this, but it returns a left join instead of an inner join, which I want.
var uhlavAktQuery = new XPQuery<UHLAVAKT>(CoreHelper.DataSession);
var ubucQuery = new XPQuery<UBUC>(CoreHelper.DataSession);
var resultBankyUcty = (from h in uhlavAktQuery
join u in ubucQuery on h.CompoundKey1.UCET equals u.UCET
group new { h, u } by new { h.CompoundKey1.UCET } into gUcty
select new
{
Ucet = gUcty.Key.UCET,
KON_STAV_MD = gUcty.Sum(k => k.h.KONSTAVMD),
KON_STAV_DAL = gUcty.Sum(k => k.h.KONSTAVDAL),
KON_STAV_MD_MENA = gUcty.Sum(k => k.h.KONSTAVMDMENA),
KON_STAV_DAL_MENA = gUcty.Sum(k => k.h.KONSTAVDALMENA),
KOD_MENY = gUcty.Max(k => k.u.KODMENY)
});
Can you help me, please?

When I was struggling to get my head around joins with LINQ, I found the following article on CodeProject very informative and helpful:
LINQ Extended Joins
With the aid of examples including diagrams he explains what joins are and presents generic extension methods for IEnumerable which implement the various join queries.

Related

Joining 6 tables together with inner joins & a left outer join - LINQ

I have 6 tables. Like this:
Here is the SQL code that I'm trying to re-code within LINQ.
SELECT dbo.TimeTable.Day, dbo.TimeTable.StartTime, dbo.TimeTable.Duration, dbo.Module.ModuleRef, dbo.Module.ModuleName, dbo.Course.CourseRef, dbo.Room.RoomRef, dbo.Room.RoomName,
dbo.Room.RoomFloor, dbo.Room.RoomNumber, dbo.Building.BuildingRef, dbo.Building.BuildingName
FROM dbo.Room INNER JOIN
dbo.TimeTable INNER JOIN
dbo.Module ON dbo.TimeTable.ModuleId = dbo.Module.Id ON dbo.Room.Id = dbo.TimeTable.RoomId INNER JOIN
dbo.Building ON dbo.Room.BuildingId = dbo.Building.Id LEFT OUTER JOIN
dbo.Course INNER JOIN
dbo.CourseModule ON dbo.Course.Id = dbo.CourseModule.CourseId ON dbo.Module.Id = dbo.CourseModule.ModuleId
If anyone could point me in the right direction of converting this to a LINQ statement? I am new to this concept of linq statements. Thanks for any help!
Try and not get overwhelmed with the fact that you have 6 tables and inner and left joins. Try to learn the concepts of joining 2 collections (Inner and Left) and then its just a matter of chaining linq together. Now the code can look a bit complicated but it really isn't.
Given the following in memory objects:
var rooms = new List<Room>();
var timeTables = new List<TimeTable>();
var modules = new List<Module>();
var buildings = new List<Building>();
var courses = new List<Course>();
var courseModules = new List<CourseModule>();
Your linq query might look like the following:
var result = rooms
.Join(timeTables,
room => room.Id,
table => table.RoomId,
(room, table) => new {room, table})
.Join(modules,
arg => arg.table.ModuleId,
module => module.Id,
(room_table, module) => new {room_table, module})
.Join(buildings,
arg => arg.room_table.room.BuildingId,
building => building.Id,
(room_table_module, building) => new {room_table_module, building})
.GroupJoin(courseModules,
arg => arg.room_table_module.module.Id,
coursemodule => coursemodule.ModuleId,
(room_table_module_building, coursemodules) => new { room_table_module_building, coursemodules})
.SelectMany(arg => arg.coursemodules.DefaultIfEmpty(),
(arg, coursemodule) => new { arg.room_table_module_building, coursemodule })
.Join(courses,
arg => arg.coursemodule.CourseId,
course => course.Id,
(room_table_module_building_coursemodule, course) => new { room_table_module_building_coursemodule, course });
The great part of LinqPad is that you have direct access to the db objects and can play around with your linq queries and see the generated sql. You can then take the sql and ensure that the execution plan looks good and can add any indexes that will optimize your queries.

Join 2 table and group 2 field in linq

I have a very simple SQL
SELECT s.shop_code
,SUM(im.amt) sum_amt
,s.cell_no#1 shop_cell
FROM tb_sn_so_wt_mst im
,tb_cm_shop_inf s
WHERE im.shop_code = s.shop_code
GROUP BY s.shop_code, s.cell_no#1)
then i try to code linq
var listResult = from warrantyMaster in listWarrantyMasters2.Records
join shopInfo in listShopInfos
on warrantyMaster.ShopCode equals shopInfo.ShopCode
i don't know group by shop code and cell no and sum atm, any one help me out of this problem
The group by syntax with some examples is explained here group clause (C# Reference) and related links.
Here is the direct translation of your SQL query (of course the field names are just my guess since you didn't provide your classes):
var query = from im in listWarrantyMasters2.Records
join s in listShopInfos
on im.ShopCode equals s.ShopCode
group im by new { s.ShopCode, s.CellNo } into g
select new
{
g.Key.ShopCode,
g.Key.CellNo,
SumAmt = g.Sum(e => e.Amt)
};
You can try this code:
var results = from warrantyMaster in listWarrantyMasters2.Records
from shopInfo in listShopInfos
.Where(mapping => mapping.ShopCode == warrantyMaster.ShopCode )
.select new
{
ShopCode = warrantyMaster.ShopCode,
ATM = listWarrantyMasters2.ATM,
ShellNo = shopInfo.ShellNo
}
.GroupBy(x=> new { x.ShopCode, x.ShellNo })
.Select(x=>
new{
ShopCode = x.Key.ShopCode,
ShellNo = x.Key.ShellNo,
SumATM = x.Sum(item=>item.ATM)
});

Left outer join off of group by dataset using linq

I am attempting to write the following SQL as a linq query.
SELECT grp.OrganisationId,
grp.OrderCount,
organisations.Name
FROM (select OrganisationId,
count(*) as OrderCount
from orders
where 1 = 1
group by OrganisationId) grp
LEFT OUTER JOIN organisations on grp.OrganisationId = organisations.OrganisationId
WHERE 1 = 1
The where clauses are simplified for the benefit of the example.
I need to do this without the use of navigational properties.
This is my attempt:
var organisationQuery = ClientDBContext.Organisations.Where(x => true);
var orderGrouped = from order in ClientDBContext.Orders.Where(x => true)
group order by order.OrganisationId into grouping
select new { Id = grouping.Key.Value, OrderCount = grouping.Count() };
var orders = from og in orderGrouped
join org in organisationQuery on og.Id equals org.Id
select(x => new OrganisationOrdersReportPoco()
{
OrganisationNameThenCode = org.Name,
TotalOrders = og.OrderCount
});
But I am getting an error of...
Type inference failed in the call to 'Join'
From previous threads, I believe this is because I have "lost the join with order" (but I don't understand why that matters when I am creating a new recordset of Organisation, Count).
Thanks!
I understand you may believe navigation properties are the solution here, but if possible, please can we keep the discussion to the join off of the group by as this is the question I am trying to resolve.
You are mixing lambda and LINQ expressions. Change select to:
select new OrganisationOrdersReportPoco()
{
OrganisationNameThenCode = org.Name,
TotalOrders = og.OrderCount
};
If i understood your model correctly you could try this instead:
var orders = ClientDBContext.Organisations.Select(org => new OrganisationOrdersReportPoco
{
OrganisationNameThenCode = org.Name,
TotalOrders = org.Orders.Count()
}).ToList();

Type inference failed in the call to 'Join'

I am getting the following error on the word "join" in the code below.
The type of one of the expressions in the join clause is incorrect.
Type inference failed in the call to 'Join'.
var organisationQuery = ClientDBContext.Organisations.Where(x => true);
var orderGrouped = from order in ClientDBContext.Orders.Where(x => true)
group order by order.OrganisationId into grouping
select new { Id = grouping.Key.Value, OrderCount = grouping.Count() };
var orders = from og in orderGrouped
join org in organisationQuery on og.Id equals org.Id
select(x => new OrganisationOrdersReportPoco()
{
OrganisationNameThenCode = org.Name,
TotalOrders = og.OrderCount
});
I don't see a problem with the join clause? Can anyone please advise?
Edit:
This is the piece of SQL I am attempting to write as LINQ.
SELECT grp.OrganisationId,
grp.OrderCount,
organisations.Name
FROM (select OrganisationId,
count(*) as OrderCount
from orders where 1 = 1 group by OrganisationId) grp
LEFT OUTER JOIN organisations on grp.OrganisationId = organisations.OrganisationId
WHERE 1 = 1
I have complicated where clauses on both orders and organisations... simplified for this example.
You are selecting into an anonymous type in the first query:
var orderGrouped = ..
select new { Id = grouping.Key.Value, OrderCount = grouping.Count() };
This 'breaks' the connection with order.
The join looks like it should work for Linq-to-Objects but it can't be converted into SQL.
You'll have to eliminate the anonymous type and somehow make a more direct connection.
I wonder why you don't simply go from Organisations? With a proper mapping using nav-properties it should look like:
from org in ClientDBContext.Organisations
select(x => new OrganisationOrdersReportPoco()
{
OrganisationNameThenCode = org.Name,
TotalOrders = org.Orders.Count
};
using the Id properties should be a little more involved but follow the same pattern.
(Credit to Giorgi Nakeuri)
I was confusing LAMBDA with LINQ expressions.
Replacing my select with this solved it.
select new OrganisationOrdersReportPoco()
{
OrganisationNameThenCode = org.Name,
TotalOrders = og.OrderCount
};

CRM LINQ Composite join "The method 'Join' is not supported" error

Im getting a "The method 'Join' is not supported" error... Funny thing is that i simply converted the 1st LINQ into the 2nd version and it doesnt work...
What i wanted to have was LINQ version #3, but it also doesnt work...
This works
var query_join9 = from s in orgSvcContext.CreateQuery(ServiceAppointment.EntityLogicalName)
join b in orgSvcContext.CreateQuery(bh_product.EntityLogicalName)
on s["bh_contract"] equals b["bh_contract"]
where ((EntityReference)s["bh_contract"]).Id == Guid.Parse("09BDD5A9-BBAF-E111-A06E-0050568B1372")
select new
{
Events = s,
Products = b
};
This doesn't
var query_join9 = from s in orgSvcContext.CreateQuery(ServiceAppointment.EntityLogicalName)
join b in orgSvcContext.CreateQuery(bh_product.EntityLogicalName)
on new { contractid = s["bh_contract"] }
equals new { contractid = b["bh_contract"] }
where ((EntityReference)s["bh_contract"]).Id == Guid.Parse("09BDD5A9-BBAF-E111-A06E-0050568B1372")
select new
{
Events = s,
Products = b
};
Also, this doesn't, which is a composite join and what i really aim for
var query_join9 = from s in orgSvcContext.CreateQuery(ServiceAppointment.EntityLogicalName)
join b in orgSvcContext.CreateQuery(bh_product.EntityLogicalName)
on new { contractid = s["bh_contract"], serviceid = s["serviceid"] }
equals new { contractid = b["bh_contract"], serviceid = s["serviceid"] }
where ((EntityReference)s["bh_contract"]).Id == Guid.Parse("09BDD5A9-BBAF-E111-A06E-0050568B1372")
select new
{
Events = s,
Products = b
};
I tried early binding and still doesnt work...
var query_join9 = from s in orgSvcContext.CreateQuery<ServiceAppointment>()
join b in orgSvcContext.CreateQuery<bh_product>()
on new { foo = s.bh_contract.Id }
equals new { foo = b.bh_Contract.Id }
where s.bh_contract.Id == Guid.Parse("09BDD5A9-BBAF-E111-A06E-0050568B1372")
select new
{
Events = s,
Products = b
};
stil not working
var query_join9 = from s in orgSvcContext.CreateQuery<ServiceAppointment>()
join b in orgSvcContext.CreateQuery<bh_product>()
on new { s.bh_contract.Id, s.ServiceId }
equals new { b.bh_Contract.Id, ServiceId = b.bh_Service }
where s.bh_contract.Id == Guid.Parse("09BDD5A9-BBAF-E111-A06E-0050568B1372")
select new
{
Events = s,
Products = b
};
But im simply trying to do the example(s) here How to do joins in LINQ on multiple fields in single join
What am i missing?
Thanks in advance
While I'm not entirely sure which CRM you're using, I think you're misunderstanding something.
In order for a LINQ query to work, there needs to be a LINQ provider for the underlying data source -- the bit of code responsible for translating chain of e.g. Join, Where, operator usage, etc, etc, into the query API of the data source. This might be SQL, some custom query language, or some chain of methods.
Two LINQ providers (such as, one for LINQ to DataSet and some custom provider you've written yourself) don't have to support the same methods and other code. The precise subset of LINQ methods (and/or other embedded statements) a LINQ provider supports is dependent on its implementation.
Looking at it like that, it's not that surprising that the LINQ provider you're using doesn't seem to comprehend the standard syntax for joins using multiple fields, or doesn't seem to comprehend the usage of anonymous types at all.
My advice is to search the documentation of the supplied LINQ provider to see which query operations it supports (perhaps there is a note about this specific mode of query not being supported). Failing that, you'll have to resort to some sort of other query -- one not involving an equijoin. Perhaps your best option is to perform the joins separately, and then intersect the two result groups. It really depends on the specifics of the case.
Have you looked at the MSDN samples. There are some multiple-column join examples there:
using (ServiceContext svcContext = new ServiceContext(_serviceProxy))
{
var list_join = (from a in svcContext.AccountSet
join c in svcContext.ContactSet
on a.PrimaryContactId.Id equals c.ContactId
where a.Name == "Contoso Ltd" && <<--- multiple join here
a.Address1_Name == "Contoso Pharmaceuticals"
select a).ToList();
foreach (var c in list_join)
{
System.Console.WriteLine("Account " + list_join[0].Name
+ " and it's primary contact "
+ list_join[0].PrimaryContactId.Id);
}
}
This other thread might be relevant

Categories

Resources