簡體   English   中英

EF Core Linq 用於不同的行

[英]EF Core Linq for distinct rows

我需要有關基於 linq 方法的查詢的幫助。 我有下面的表格。

項目表

ItemId | Itemname
  1    | Item1

狀態表

StatusId | Status
   S1    | NotOk
   S2    | Ok
   S3    | Unknown

我有一個如下映射表:它將具有如下所示的映射,並帶有重復的記錄。 為簡單起見,我沒有包括所有列。

項目狀態

ItemId | StatusId
   1   | S1
   1   | S1
   1   | S2

需要 linq 方法的幫助,用於顯示如下數據

ItemName | Status
  Item1  | NotOK, OK

但是當我嘗試使用 linq(基於方法而不是基於查詢)時,我得到了如下所示的重復項。 我不希望包含重復的記錄。

ItemName | Status
   Item1 | NotOK, NotOk, OK

我無法發布 linq 因為它太復雜了。 我簡化了場景並在此處發布。 請為此場景建議正確的基於 linq 方法的方法

我已經給出了高級 linq 查詢(不是那么准確,我只是添加以供參考)

var dataQueryable = context.ItemTable
                .Join(context.ItemStatus.Select(a => a.ItemId).Distinct(), item=>item.ItemId, id=>id,(item,id) =>
                    new ReturnObject
                    {
                        ItemId = item.ItemId,
                        ItemName = item.ItemName,
                        Status = item.ItemStatus
                            .Where(e => e.ItemId == item.ItemId)
                            .Select(result => new ResultReturnObject()
                            {
                                Status = result.status
                            })
                            .ToList()
                    })
                .AsQueryable();

(1) 我有一個如下的映射表:它會有如下的映射和重復的記錄。

(2) 如果有辦法避免重復,那將有所幫助

對於多對多表來說,這是一種不受歡迎的方法。 您可以嘗試重復行的即時解決方案,但這不是正確的解決方案。 首先,你需要清理臟數據,然后你需要避免它們,尤其是插入它們。

|--------|----------|
| ItemId | StatusId |
|--------|----------|
|    1   |    1     | OK
|--------|----------|
|    1   |    2     | OK
|--------|----------|
|    1   |    1     | N/A
|--------|----------|   

您應該使用復合鍵來防止在插入查詢時出現重復行。 因此,db 向開發環境拋出'Cannot insert duplicate key'異常。

public class ApplicationDbContext : DbContext
{
    public DbSet<ItemStatus> ItemStatuses { get; set; }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        //Other relationships
        modelBuilder.Entity<ItemStatus>()
                    .HasKey(x => new { x.ItemId, x.StatusId});
    }
}

https://docs.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#alternate-keys

我需要有關基於 linq 方法的查詢的幫助。 我有下面的表格。

項目表

ItemId | Itemname
  1    | Item1

狀態表

StatusId | Status
   S1    | NotOk
   S2    | Ok
   S3    | Unknown

我有一個如下映射表:它將具有如下所示的映射,並帶有重復的記錄。 為簡單起見,我沒有包括所有列。

項目狀態

ItemId | StatusId
   1   | S1
   1   | S1
   1   | S2

需要 linq 方法的幫助,用於顯示如下數據

ItemName | Status
  Item1  | NotOK, OK

但是當我嘗試使用 linq(基於方法而不是基於查詢)時,我得到了如下所示的重復項。 我不希望包含重復的記錄。

ItemName | Status
   Item1 | NotOK, NotOk, OK

我無法發布 linq 因為它太復雜了。 我簡化了場景並在此處發布。 請為此場景建議正確的基於 linq 方法的方法

我已經給出了高級 linq 查詢(不是那么准確,我只是添加以供參考)

var dataQueryable = context.ItemTable
                .Join(context.ItemStatus.Select(a => a.ItemId).Distinct(), item=>item.ItemId, id=>id,(item,id) =>
                    new ReturnObject
                    {
                        ItemId = item.ItemId,
                        ItemName = item.ItemName,
                        Status = item.ItemStatus
                            .Where(e => e.ItemId == item.ItemId)
                            .Select(result => new ResultReturnObject()
                            {
                                Status = result.status
                            })
                            .ToList()
                    })
                .AsQueryable();

幾個月前我做了類似的事情,我試圖重新創建,這不是最好的解決方案,但它可以幫助找到更好的解決方案。 首先是按ItemNameStatus應用組以消除重復

var result =
            from p in items
            select new
            {
                noDuplicated = (from pc in itemStatuses
                           join c in status on pc.StatusId equals c.StatusId
                           where pc.ItemId == p.ItemId
                           group p by new { p.ItemName,  c.Estatus }
                           into mygroup
                           select new { 
                               ItemName = mygroup.Key.ItemName, 
                               StatusName = mygroup.Key.Estatus 
                           })
            };

之后你會得到這個結果:

ItemName | Status
Item1 | NotOK 
Item1 | OK

最后,您只能通過ItemName應用另一個組

var grouped = result.Select(a => a.noDuplicated).SingleOrDefault()
                .GroupBy(e => new { e.ItemName }).ToList()
                .Select(eg => new
                {
                    ItmName = eg.Key.ItemName,
                    StatList = string.Join(",", eg.Select(i => i.StatusName))
                });

在 LINQ 中,每當您想要“項目及其子項目”,例如“學校及其學生”、“作者及其書籍”、“客戶及其訂單”,或者在您的情況下:“項目及其狀態”時,請考慮使用GroupJoin 的重載

在一對多的關系中,這是相當簡單的。 您在ItemsStatusses之間有一個多對多的關系。 因此,您需要先與聯結表ItemStatus進行 GroupJoin,然后才能獲取屬於該ItemStatusses

var itemsWithTheirStatusses = dbContext.ItemsTable.GroupJoin(
    dbContext.ItemsStatusses,            // GroupJoin ItemsTable with junction table
    item => item.Id,                     // from every Item take the Id
    itemStatus => itemStatus.ItemId,     // from every itemStatus take the itemId

    // Parameter resultSelector: from every Item with its zero or more ItemStatusses
    // make one new object
    (item, itemStatussesOfThisItem) => new ...

我在這里所做的是,我拿走了 ItemsTable 中的所有項目。 從這張表中的每個項目中,我都獲取了 ID。 我搜索了 ItemsStatusses 表中引用此 ID 的每一行。

所以現在我有一個 Item 和所有引用這個 Item 的 ItemStatusses,我需要制作一個新的 object。 每個 ItemStatus 都有一個StatusId ,因此您可以簡單地獲取屬於此 Id 的狀態。

但是,您的問題是您有幾個itemStatussesOfThisItem引用相同的Status ,換句話說:具有相同的StatusId值。

您可以先獲取屬於此項目的狀態,然后刪除重復項。 如果您首先刪除重復的 StatusId,然后獲取具有此 Id 的狀態,則效率更高。

繼續 GroupJoin:

(item, itemStatussesOfThisItem) => new
{
    // Select only the Item properties that you plan to use:
    Id = item.Id,

    // if desired, add other item properties:
    Name = item.Name,
    ...

    // process the itemStatussesOfThisItem. You only want the Status
    // from every itemStatus of this item,  select only the StatusId
    // Remove the duplicate StatusIds
    // Get the Status with this StatusId
    // and select the Status properties that you want:
    Statusses = itemStatussesOfThisItem
        .Select(itemStatus => itemStatus.StatusId)   // get all StatusIds
        .Distinct()                                  // remove duplicate StatusIds
        .Select(statusId => dbContext.Statusses      // get the Status with this Id
             .Where(status => status.Id == statusId)
             
             // you are only interested in property Status:
             .Select(status => status.Status)
             .ToList(),
});

例子:

 Statusses          ItemsTable         ItemsStatusses
Id   Status         Id  Name            ItemId  StatusId
20   Ok             10   A                10       20 
21   NotOk          11   B                11       22
22   Unknown        12   C                11       22
                    13   D                10       21
                                          10       20
                                          11       20
                                          13       21
                                          13       21

在參數 resultSelector 的開頭,您有(item, itemStatussesOfThisItem)

  • 項目 [10] 及其 ItemStatusses [10, 20] [10, 21] [10, 20]
  • 項目 [11] 及其 ItemStatusses [11, 22] [11, 22] [11, 20]
  • 帶有空 ItemStatusses 的項目 [12]
  • 項目 [13] 和項目狀態 [13, 21] [13, 21]

對於這些項目中的每一項,您都制作了一個新的 object,它具有兩個屬性: IdStatusses Id 等於 Item.Id。

Statusses :從它的所有 ItemStatusses 中,只取 StatusId,並刪除重復項:

  • 項目 [10]:{[10, 20] [10, 21] [10, 20]} => {20, 21, 20} => {20, 21}
  • 項目 [11]:{[11, 22] [11, 22] [11, 20]} => {22, 22, 20} => {22, 20}
  • 項目 [12]:{} => {} => {}
  • 項目 [13]:{[13, 21] [13, 21]} => {21, 21} => {21}

現在您有了唯一的 StatusIds,這些狀態的描述很容易:

.Select(statusId => dbContext.Statusses.
       .Where(status => status.Id == statusId)
       .Select(status => status.StatusDescription)
       .ToList();

結果:

  • 項目 ID 10,狀態為 Ok,NotOk
  • 項目 ID 11,狀態正常,未知,
  • 沒有任何狀態的項目 ID 12
  • 狀態為 NotOk 的項目 ID 13

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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