簡體   English   中英

將SQL分組查詢轉換為LINQ查詢

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM