I want to combine results from 4 tables and select specific fields using LINQ. Please bear with me since I have not done complex LINQ queries.
Table 1 - Subscriber<
The results is not including subscribers without subscriptions.
When writing queries, always first try to determine the root entity. You're interested in subscriptions, so it seems obvious to take Subscription
as root entity. But in fact you want to see whether or not subscribers have subscriptions, and if so, which. Subscriber is the root entity, so start the query there.
Figured out how to concatenate the string
Sure, db.Subscriptions.ToList()
does allow you to do anything that LINQ-to-objects has in store, but it's very inefficient. First, you pull all Subscription
data into memory. Then, in var model = (from s in query ...
you join with DbSet
s that each pull all their data into memory. (Because query
is IEnumerable
and, hence, can't be combined with IQueryable
s into one expression and then translated into one SQL statement).
The strategy for using non-supported methods in LINQ-to-Entities queries is: query the exact amount of data --no more, no less-- then continue in memory.
Both points amount to this query:
var query = from s in db.Subcribers // root entity
select new
{
Subscriber_ID = s.Subscriber_ID,
FirstName = s.SubscriberFirstName,
LastName = s.SubscriberLastName,
Address1 = s.SubscriberAddress1,
Address2 = s.SubscriberAddress2,
Email = s.SubscriberEmail,
Organization = s.SubscriberOrganizationName,
Phone = s.SubscriberPhone,
City = s.SubscriberCity,
Zip = s.SubscriberZipcode,
// Navigation properties here
State = (s.SubscriberState_ID == 54) ? s.SubscriberState : s.State.StateName,
StateAbbv = (s.SubscriberState_ID == 54) ? s.SubscriberState : s.State.StateAbbreviation,
Country = s.Country.CountryName,
// Empty list when no subscriptions
Pubs = s.Subscriptions.Select(x => x.SubscriptionPublication).Distinct()
};
var result = query.AsEnumerable() // continue in memory
Select(s => new SubscriberGridViewModel
{
Subscriber_ID = s.Subscriber_ID,
FirstName = s.FirstName,
LastName = s.LastName,
Address1 = s.Address1,
Address2 = s.Address2,
Email = s.Email,
Organization = s.Organization,
Phone = s.Phone,
City = s.City,
State = s.State,
StateAbbv = s.StateAbbv,
Country = s.Country,
Zip = s.Zip
Pub = string.Join(", ", s.Pubs)
}));
Of course, if you're querying almost all fields from Subscriber
this can be a bit less verbose: select new { Subscriber = s, Pubs = .. }
etc. But I usually experience that the performance gain of narrowing down the SQL result set is greatly underestimated as compared to shortening it by filtering.