Reputation: 485
I'm trying to use lambda to join 5 tables. What I would like to know is if I'm doing it right and if there's a better way of doing it. Any suggestion is much appreciated.
var myList = _context.Event
.Join(_context.EventHost,
e => e.EventHostId,
eh => eh.Id,
(e, eh) => new { Event = e, EventHost = eh })
.Join(_context.EventAddress,
eh => eh.EventHost.EventAddressID,
ea => ea.ID,
(eh, ea) => new { EventAddress = ea, EventHost = eh })
.Join(_context.OrderHeaderGroup,
ea => ea.EventHost.Event.Id,
ohg => ohg.EventId,
(ea, ohg) => new { EventAddress = ea, OrderHeaderGroup = ohg })
.Join(_context.OrderHeader,
ohg => ohg.OrderHeaderGroup.OrderHeaderGroupID,
oh => oh.OrderHeaderGroupID,
(oh, ohg) => new { OrderHeader = oh, OrderHeaderGroup = ohg })
.Select(c => new {
c.OrderHeader.OrderHeaderGroup.EventId,
c.OrderHeader.EventAddress.EventAddress.Name,
c.OrderHeader.EventAddress.EventAddress.Phone,
c.OrderHeader.EventAddress.EventAddress.Address1,
c.OrderHeader.EventAddress.EventAddress.Address2,
c.OrderHeader.EventAddress.EventAddress.City,
c.OrderHeader.EventAddress.EventAddress.Country,
c.OrderHeader.EventAddress.EventAddress.PostalCode,
c.OrderHeader.EventAddress.EventAddress.Email,
c.OrderHeader.EventAddress.EventHost.Event.ConsultantId,
c.OrderHeader.EventAddress.EventHost.Event.StartDate,
c.OrderHeader.EventAddress.EventHost.Event.EndDate,
}).Where(x => x.ContactId == contactId && x.StartDate >= newStartDate && x.EndDate <= newEndDate).ToList();
Upvotes: 1
Views: 144
Reputation: 6238
The issue here isn't preferential code readability. Which, BTW, I think Lambda is far more readable than Query form. But that's because I'm a programmer.
The issue is that you are trying to take a SQL Developer's perspective and SHOVE It into programming. I did that when LinqToEntities was first a thing, where I start in SSMS et al, I write a query, then I do Transliteration
into C#.
The solution is to use your ORM. If you use a feature rich ORM, you should have something called Navigation Properties
. These already have implicit joins for you that are either implicitly, or explicitly declared in your Fluent mapping. So you shouldn't have to re-describe every join every time you write a LINQ statement.
If you trust the language and configure your system correctly, you can end up with something like this:
// This is not shortened, this should be the whole thing.
var myList = _context.OrderHeader
.Where(x => x.EventAddress.Something.ContactId == contactId
&& x.EventAddress.Something.StartDate >= newStartDate
&& x.EventAddress.Something.EndDate <= newEndDate)
.Select(c => new DetailEntityView(c)).ToList();
I also suggest using "View" classes. These aren't entities that are configured to persist to the DB, but are like DB Views, in C#. They are less used classes that just transfer data.
public class DetailEntityView
{
public int EventId { get; set; }
public string Name { get; set; }
// ... etc
public DetailEntityView(OrderHeader c)
{
EventId = c.OrderHeaderGroup.EventId;
Name = c.EventAddress.EventAddress.Name;
// ... etc
}
}
Now, some ORMs are less featured than the EF's and NH's of the world. So in that case, I'm sorry you or your team chose something else.
Also, all of your joins are on IDs, which is as it should be. But SOME Custom queries join on field that are not constrained, like name fields or other values. In those cases, you do need to add those specific joins to your query. But 1.) Ew. And 2.) Why? And 3.) Then you can do what you did in your OP.
Upvotes: 2
Reputation: 26342
Yes, use the query syntax, as is the recommendation from Microsoft: Check here
At compile time, query expressions are converted to Standard Query Operator method calls according to the rules set forth in the C# specification. Any query that can be expressed by using query syntax can also be expressed by using method syntax. However, in most cases query syntax is more readable and concise.
from event in _context.Event
join eventHost in _context.EventHost
on event.EventHostId equals eventHost.Id
join eventAddress in _context.EventAddress
on eventHost.EventAddressId equals eventAddress.Id
// etc
select new {/*You new anonymous type here*/}
Upvotes: 2