[英]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();
幾個月前我做了類似的事情,我試圖重新創建,這不是最好的解決方案,但它可以幫助找到更好的解決方案。 首先是按ItemName和Status應用組以消除重復
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 的重載。
在一對多的關系中,這是相當簡單的。 您在Items
和Statusses
之間有一個多對多的關系。 因此,您需要先與聯結表ItemStatus
進行 GroupJoin,然后才能獲取屬於該Item
的Statusses
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)
:
對於這些項目中的每一項,您都制作了一個新的 object,它具有兩個屬性: Id
和Statusses
。 Id 等於 Item.Id。
Statusses
:從它的所有 ItemStatusses 中,只取 StatusId,並刪除重復項:
現在您有了唯一的 StatusIds,這些狀態的描述很容易:
.Select(statusId => dbContext.Statusses.
.Where(status => status.Id == statusId)
.Select(status => status.StatusDescription)
.ToList();
結果:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.