我想合并4个表的结果,并使用LINQ选择特定的字段。 因为我还没有完成复杂的LINQ查询,所以请多多包涵。
表1-订户
表2-订阅
表3-状态
表4-国家
注意:订户可以有0个,1个或多个订阅。 这意味着外键(SubscriberID)是Subscription表的一部分
查询应从订户表一次返回每个订户。订户是否有订阅无关紧要。我需要在结果列表中包含所有订户。
这是复杂的地方:
在结果列表中,我想包含一个属性“ PubName”。此属性是一个逗号分隔的字符串,带有订阅者所订阅的发布者名称。 PubName是“订阅”表中的一列。
我已经用SQL编写了一个存储过程,并使用了一个附加功能来构造每个订阅者的PubName字段。
例如:我们的列表有3行:
- 维克多(Victor W),位于纽约W 45th st#43#43,“ Mag A,Mag B,Mag C”
(Victor订阅了Mag A,B和C)
- 丹,564 E 23rd st FL3,纽约,纽约,“ Mag A,Mag D,Mag F”
(Dan已订阅Mag A,D和F)
- Nicole,78 E 12rd st#3,纽约,纽约,“ NULL”
(Nicole没有订阅)
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语句内的商店表达式。
弄清楚如何连接字符串:
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();
结果不包括没有订阅的订阅者。 有任何解决方法的想法吗?
答案 0 :(得分:2)
结果不包括没有订阅的订阅者。
在编写查询时,始终首先尝试确定根实体。您对订阅感兴趣,因此显然可以将Subscription
作为根实体。但实际上,您想查看订户是否有订阅,如果有,则有。订户是根实体,因此从那里开始查询。
弄清楚如何连接字符串
当然,db.Subscriptions.ToList()
确实允许您执行LINQ到对象存储中的任何操作,但是效率很低。首先,将所有Subscription
数据拉入内存。然后,在var model = (from s in query ...
中加入DbSet
,每个将所有其数据拉入内存。 (因为query
是IEnumerable
,因此不能与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 = .. }
等。但是我通常会体验到缩小性能< / em>与通过过滤缩短 的结果相比,SQL结果集被大大低估了。
答案 1 :(得分:1)
不是真的是LINQ,而是LINQ to Entities。您正在使用实体框架吗?您的模型中是否定义了关系?如果您的数据库中有外键,并且首先在带有数据库的Entity Framework中构建模型,它将为您映射所有实体关系。
如果是,则可以执行以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public class Subscriber{
public string Name {get;set;}
public List<Subscription> 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<Subscriber>{
new Subscriber{
Name = "Arnold",
Subscriptions = new List<Subscription>(){
new Subscription{
Name = "Subscription A"
},
new Subscription{
Name = "Subscription B"
},
new Subscription{
Name = "Subscription C"
}
}
},
new Subscriber{
Name = "Betty",
Subscriptions = new List<Subscription>()
},
new Subscriber{
Name = "Christopher",
Subscriptions = new List<Subscription>(){
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,订阅:Subscription A