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

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.

Related

Equivalent of INNER JOIN ... WHERE in NHibernate

I have class Category that contains a List<Subcategory>.
Using LINQ (preferrably), I want to get all Categoriess but filter their Subcategories such that the resulting query would look like:
SELECT * FROM categories
LEFT JOIN subcategories ON subcategories.category_Id = categories.id WHERE subcategories.Retired = false
I have tried:
session.QueryOver<Category>()
.Left.JoinQueryOver(c => c.Subcategories, () => subcategoryAlis, s => !s.Retired)
.List<Category>())
And a few other hacky looking tricks but I can't seem to get the results I need. The above query produces completely useless results with the same entries appearing multiple times and many missing.
It's been a while since I've used NHibernate, but I would do it with some dedicated DTO classes for converting to Json, not directly from the entities. I think something along the lines of the following linq query should work:
from c in session.Query<Category>
select new CategoryDto {
Name = c.Name, //and other properties
SubCategories = c.SubCategories
.Where(sc => !sc.Retired)
.Select(sc => new SubCategoryDto { ... })
.ToList()
}

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();

Entity Framework Join Query based on SQL statement

I have SQL like this:
SELECT * FROM [dbo].[INSTANCE]
INNER JOIN dbo.TIME_INSTANCE on dbo.INSTANCE.INSTANCE_ID = dbo.TIME_INSTANCE.INSTANCE_ID
where customer_id=15 and TIME_ID = 1013
And I'm trying to use Entity framework to get this. I can pull back the instances from the instances table like this:
DBContext.Instances.Where(x => x.CustomerID == id && x.StartDateTime >= dateRange).OrderBy(x => x.StartDateTime).AsQueryable();
How do I perform the join like in the SQL above so that I do an inner join on the time_instance table?
quietgrit...I assume that your looking for a Lambda that will do the same thing?
I was able to mock this up and run it against my database. I copied the names of your objects into the below query. I used <theNameOfYourDataBase>Container instead of DbContext but the jest of the Lambda is the same. Let me know if this helps.
private myDbContainer db = new myDbContainer();
var myJoin = db.INSTANCE
.Join(db.TIME_INSTANCE , i => i.PK_Category, ti => ti.FK_INSTANCE, ((i, ti) => new { INSTANCE = i,TIME_INSTANCE = ti }))
.Select(joinedStuff => new {
joinedStuff.INSTANCE.customer_id,//Fill in the rest of the properties you want in your query
joinedStuff.TIME_INSTANCE.TIME_ID
}).Where(n => n.TIME_ID == 1013 && n.customer_id == 15);//Add an .OrderBy() and or .GroupBy()
Best Wishes,
Bill

Linq Group by and inner join

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.

Join array to EF query

I get the following error when trying to join an array to the Linq-to-EF query
An error occurred while executing the command definition. See the inner exception for details. Some part of your SQL statement is nested too deeply. Rewrite the query or break it up into smaller queries.
The code is as follows:
var vids = new List<string>();
using (var ctx = new MyDbContext())
{
var qry = ctx.Pickups.Where(p => p.UserName == User.Identity.Name);
if (someBoolean)
{
var v = GetVids(); // get the list of Ids from a web service
vids.AddRange(v);
}
if (vids.Count() > 0)
{
qry = qry.Join(vids, p => p.VId, v => v, (v, p) => p);
}
var data = qry
.Select(p => new
{
// etc.
});
}
The problem is that the web service is not associated with the DB I'm using EF with, otherwise, I'd just do the join against the tables in the DB. The number of Id's I get back from the web service could be upwards of a hundred or so (usually 5-10). If I comment out the Join, the code works fine, so I know the error is in the Join. With just a few (up to about 30) ids in vids, the join works perfectly.
What do you recommend to remedy this problem? The only thing I could think of was to insert the list of IDs into the DB and do the join that way. That doesn't seem too appealing to me.
Try to replace if (vids.Count() > 0) with:
if (vids.Count > 0)
{
qry = qry.Where(arg => vids.Contains(arg.VId));
}
This will work only if vids is less then 2100 elements, as this will be translated to IN (x, y, .., n) condition.
If you use entity framework 3.5, then Contains will not work. You can find possible solution here: 'Contains()' workaround using Linq to Entities?

Categories

Resources