我在尝试将SQL查询转换为LINQ时遇到了麻烦。 假设,我们有以下数据结构:
class Movie
{
public Guid ID { get; set; }
// navigation properties
public virtual ICollection<Commercial> Commercials { get; set; }
public virtual ICollection<Spectator> Spectators { get; set; }
}
class Commercial
{
public Guid ID { get; set; }
public Guid MovieID { get; set; }
public string ProductType { get; set; }
// navigation property
public virtual Movie Movie { get; set; }
}
class Spectator
{
public Guid ID { get; set; }
public Guid MovieID { get; set; }
public int Age { get; set; }
// navigation property
public virtual Movie Movie { get; set; }
}
现在让我们说,我想知道,有多少观众看过某个产品类别的广告。在SQL中,它看起来像这样:
select Commercial.ProductType, count(distinct Spectator.ID)
from Spectator
join Movie on Spectator.MovieID = Movie.ID
join Commercial on Commercial.MovieID = Movie.ID
where Spectator.Age > 60 # optional filter
group by Commercial.ProductType;
首先,我尝试使用GroupBy()
功能,但由于多对多关系,我没有找到按商业产品类型对观众进行分组的方法。
然后我尝试了类似的东西:
var query = db.Commercials.Where(x => x.Age > 60).GroupJoin(
db.Spectators,
c => c.MovieID,
s => s.MovieID,
(c, g) => new { ProductType = c.ProductType, Count = g.Distinct().Count() });
这看起来很有希望,但没有回复预期的结果。
答案 0 :(得分:1)
您拥有所有这些不错的导航属性,因此您无需加入LINQ。导航属性可以被视为硬编码连接,可以防止重复,冗长和容易出错的代码(例如,使用错误的连接属性)。
了解这一点,您可以考虑使用查询来获取数据。它并不像看起来那么微不足道(而且正如我最初想的那样)。
在一部电影中可能会有n
个广告,所以如果您只计算每部电影和广告的观众数量,结果太高(观众人数的n
倍)。你必须计算独特的观众。这些计数应按ProductType
分组。这就把我们带到了这个问题:
var query = from c in db.Commercials
group c by c.ProductType into cgroup
select new
{
ProductType = cgroup.Key,
NumberOfSpectators = cgroup.SelectMany(c => c.Movie.Spectators
.Where(s => s.Age > 60)
.Select(s => s.Id)).Distinct()).Count()
};
答案 1 :(得分:0)
你的数据库之间有关联吗? 如果是,您的实体框架生成的模型必须如下:
public class Receiver
{
public int LetterId { set; get; }
public Letter Letter { set; get; }
public Country Country { set; get; }
}
public class Letter
{
public int Id { set; get; }
public int SenderId { set; get; }
public Sender Sender { set; get; }
public IEnumerable<Receiver> Receivers { set; get; }
}
public class Sender
{
public int Id { set; get; }
public Country Country { set; get; }
public IEnumerable<Letter> Letters { set; get; }
}
public class Country
{
public int Id { set; get; }
}
然后你的上下文有3种类型:
IEnumerable<Receiver> receivers = new List<Receiver>();
IEnumerable<Letter> leters = new List<Letter>();
IEnumerable<Sender> senders = new List<Sender>();
所以你的回答是这样的:
var results = from receiver in receivers
from letter in leters
from sender in senders
where receiver.LetterId == letter.Id &&
sender.Id == letter.SenderId
select
new Result
{
Country = sender.Country,
CountOfCountry = sender.Letters.Select(x => x.Receivers).Distinct().Count()
};
ResultClass是:
public class Result
{
public Country Country { set; get; }
public int CountOfCountry{ set; get; }
}
如果你把你的班级图表,我可以帮助你更好!
答案 2 :(得分:0)
我做了一些小样本。
public class Letter
{
public int Id { get; set; }
public int SenderId { get; set; }
}
public class Sender
{
public int Id { get; set; }
public string Country { get; set; }
}
public class Receiver
{
public int Id { get; set; }
public int LetterId { get; set; }
public string Country { get; set; }
}
class StackOverflow_SQLtoLinq
{
static void Main(string[] args)
{
List<Letter> lstLetters = new List<Letter>() {
new Letter(){Id=1,SenderId=1},
new Letter(){Id=2,SenderId=2},
new Letter(){Id=3,SenderId=3}
};
List<Sender> lstSenders = new List<Sender>() {
new Sender(){Id=1,Country="IND"},
new Sender(){Id=2,Country="US"},
new Sender(){Id=3,Country="NZ"}
};
List<Receiver> lstReceivers = new List<Receiver>() {
new Receiver(){Id=1,LetterId=1,Country="IND"},
new Receiver(){Id=2,LetterId=11,Country="US"},
new Receiver(){Id=3,LetterId=1,Country="NZ"},
};
var data = (from receiver in lstReceivers
join letter in lstLetters on receiver.LetterId equals letter.Id
join sender in lstSenders on letter.SenderId equals sender.Id
group sender by new { id = sender.Id, country = sender.Country } into finalData
select new
{
country = finalData.Key.country,
Count = finalData.Distinct().Count()
}).ToList();
}
}
最后在数据变量中有数据。