Complex Linq查询无法按预期工作

我想组合4个表的结果,并使用LINQ选择特定的字段。 请耐心等待,因为我没有完成复杂的LINQ查询。

表1 – 订户

表2 – 订阅

表3 – 国家

表4 – 国家

注意:订户可以拥有0,1或多个订阅。 这意味着外键(SubscriberID)是Subscription表的一部分

查询应该从订户表中返回每个订户一次。 订户是否有订阅并不重要。 我需要在结果列表中拥有所有订阅者。

这是它变得复杂的地方:

在结果列表中,我想要包含一个属性’PubName’。 此属性是逗号分隔的字符串,其中包含订阅者订阅的pub名称。 PubName是Subscription表中的一列。

我在SQL中编写了一个存储过程,使用附加函数构造每个订阅者的PubName字段。

例如:我们的列表有3行:

  1. Victor,123 W 45th st#43,New York,NY,’Mag A,Mag B,Mag C’

(Victor订阅Mag A,B和C)

  1. Dan,564 E 23rd st FL3,New York,NY,’Mag A,Mag D,Mag F’

(Dan订阅Mag A,D和F)

  1. Nicole,78 E 12rd st#3,New York,NY,’NULL’

(妮可没有订阅)

var model = await ( from subscriber in db.Subscribers // left join from state in db.States.Where(s => s.State_ID == subscriber.SubscriberState_ID).DefaultIfEmpty() // left join from country in db.Countries.Where(s => s.Country_ID == subscriber.SubscriberCountry_ID).DefaultIfEmpty() orderby subscriber.Subscriber_ID descending select new SubscriberGridViewModel { Subscriber_ID = subscriber.Subscriber_ID, Pub = GetPubName(subscriber.Subscriber_ID).ToString(), FirstName = subscriber.SubscriberFirstName, LastName = subscriber.SubscriberLastName, Address1 = subscriber.SubscriberAddress1, Address2 = subscriber.SubscriberAddress2, Email = subscriber.SubscriberEmail, Organization = subscriber.SubscriberOrganizationName, Phone = subscriber.SubscriberPhone, Zip = subscriber.SubscriberZipcode }).ToListAsync(); private static string GetPubName(int? subscriber_id) { string pubs = string.Empty; try { var db = new CirculationEntities(); var model = db.Subscriptions.Where(s => s.Subscriber_ID == subscriber_id).ToList(); foreach(Subscription sub in model) { if (string.IsNullOrEmpty(pubs)) pubs = sub.SubscriptionPublication; else pubs = ", " + sub.SubscriptionPublication; } return pubs; } catch { return "EMPTY"; } } 

使用以下代码我收到此错误:

“LINQ to Entities无法识别方法’System.String GetPubName(System.Nullable`1 [System.Int32])’方法,并且此方法无法转换为商店表达式。”

我理解错误。 无法将方法转换为LINQ语句中的存储表达式。

  1. 在LINQ中可以实现这一点吗? 如果是这样,有人可以告诉我怎么样? 我无法找到解决方案。

如何结合弦乐

 var query = from subscription in db.Subscriptions.ToList() group subscription by subscription.Subscriber_ID into g select new { Subscriber_ID = g.Key, Pub = string.Join(", ", g.Select(x => x.SubscriptionPublication).Distinct()) }; var model = (from s in query join subscriber in db.Subscribers on s.Subscriber_ID equals subscriber.Subscriber_ID join state in db.States on subscriber.SubscriberState_ID equals state.State_ID join country in db.Countries on subscriber.SubscriberCountry_ID equals country.Country_ID select new SubscriberGridViewModel { Subscriber_ID = subscriber.Subscriber_ID, Pub = s.Pub, FirstName = subscriber.SubscriberFirstName, LastName = subscriber.SubscriberLastName, Address1 = subscriber.SubscriberAddress1, Address2 = subscriber.SubscriberAddress2, Email = subscriber.SubscriberEmail, Organization = subscriber.SubscriberOrganizationName, Phone = subscriber.SubscriberPhone, City = subscriber.SubscriberCity, State = (subscriber.SubscriberState_ID == 54) ? subscriber.SubscriberState : state.StateName, StateAbbv = (subscriber.SubscriberState_ID == 54) ? subscriber.SubscriberState : state.StateAbbreviation, Country = country.CountryName, Zip = subscriber.SubscriberZipcode }).ToList(); 

结果不包括没有订阅的订阅者。 任何想法如何解决它?

结果不包括没有订阅的订阅者。

编写查询时,始终首先尝试确定根实体。 您对订阅感兴趣,因此将Subscription作为根实体显而易见。 但实际上你想看看订阅者是否有订阅,如果是,那么。 订阅者是根实体,因此在那里启动查询。

弄清楚如何连接字符串

当然, db.Subscriptions.ToList()允许您执行LINQ-to-objects存储的任何操作,但效率非常低。 首先,将所有Subscription数据拉入内存。 然后,在var model = (from s in query ...你加入DbSet ,每个都将它们的所有数据都拉入内存。(因为queryIEnumerable ,因此,不能与IQueryable结合成一个表达式然后翻译成一个SQL语句)。

在LINQ-to-Entities查询中使用不受支持的方法的策略是:查询确切的数据量 – 不多,不少 – 然后在内存中继续。

这两个点都相当于此查询:

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

当然,如果您从Subscriber查询几乎所有字段,这可能会稍微冗长: select new { Subscriber = s, Pubs = .. }等。但我通常会体验到缩小 SQL结果集的性能提升与通过过滤缩短它相比,被大大低估了。

这不是LINQ在这里绊倒的,它是LINQ to Entities。 您使用的是Entity Framework吗? 您的模型是否具有其中定义的关系? 如果您的数据库中有外键,并且首先在Entity Framework中使用数据库构建模型,它将为您映射所有实体关系。

如果是,您可以执行以下操作:

 using System; using System.Collections.Generic; using System.Linq; public class Program { public class Subscriber{ public string Name {get;set;} public List Subscriptions{get;set;} } public class Subscription{ public string Name {get;set;} } public class MyViewModelItem{ public string SubscriberName{get;set;} public string SubscriptionNames {get;set;} } public static void Main() { Console.WriteLine("Hello World"); // create some dummy data var data = new List{ new Subscriber{ Name = "Arnold", Subscriptions = new List(){ new Subscription{ Name = "Subscription A" }, new Subscription{ Name = "Subscription B" }, new Subscription{ Name = "Subscription C" } } }, new Subscriber{ Name = "Betty", Subscriptions = new List() }, new Subscriber{ Name = "Christopher", Subscriptions = new List(){ new Subscription{ Name = "Subscription A" } } } }; // here's the query and it becomes much simpler var myViewModel = data .Select(i=> new MyViewModelItem{ SubscriberName = i.Name, SubscriptionNames = string.Join(", ", i.Subscriptions.Select(j=>j.Name)) }) .ToList(); // this shows the output foreach(var item in myViewModel){ Console.WriteLine(string.Format("subscriber: {0}, subscriptions: {1}",item.SubscriberName,item.SubscriptionNames)); } } } 

输出:

Hello World订阅者:Arnold,订阅:订阅A,订阅B,订阅C订阅者:Betty,订阅:订阅者:Christopher,订阅:订阅A