[英]Translating SQL group-by query to LINQ query
我在嘗試將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() });
這看起來很有希望,但是沒有返回預期的結果。
您擁有所有這些不錯的導航屬性,因此無需加入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()
};
您的數據庫之間有關系嗎? 如果是,則由實體框架生成的模型必須如下所示:
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; }
}
如果您放上課程表,我會更好地幫助您!
我已經做了小樣。
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();
}
}
最后在data中有一個data變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.