Complex Linq query is not working as expected

后端 未结 2 864
粉色の甜心
粉色の甜心 2021-01-07 14:05

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<

2条回答
  •  不要未来只要你来
    2021-01-07 15:04

    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 DbSets that each pull all their data into memory. (Because query is IEnumerable and, hence, can't be combined with IQueryables 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.

提交回复
热议问题