如何解决EF Core Linq用于不同的行
我需要有关基于linq方法的查询的帮助。我在下面的桌子。
ItemTable
ItemId | Itemname
1 | Item1
状态表
StatusId | Status
S1 | NotOk
S2 | Ok
S3 | Unknown
我有一个映射表,如下所示:它将具有与重复记录类似的如下映射。为简单起见,我没有包括所有列。
ItemStatus
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查询现在看起来像什么?您是否尝试过使用Distinct()?
https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netcore-3.1
,几个月前,我尝试重新创建类似的东西,虽然它不是最佳解决方案,但它可以帮助寻找更好的解决方案。 首先,应用 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中,每当需要“带有子项目的项目”,例如“带有学生的学校”,“带有书的作者”,“带有订单的客户”,或者在您的情况下:“带有状态的项目”,请考虑使用overloads of GroupJoin中的一个。
在一对多关系中,这非常简单。您在Items
和Statusses
之间存在多对多关系。因此,在获取属于该ItemStatus
的{{1}}之前,您需要使用联接表Statusses
进行GroupJoin
Item
我在这里所做的是,我将ItemsTable中的所有Items都带走了。我从该表的每个项目中提取了ID。我在ItemsStatusses表中搜索了引用此ID的每一行。
所以现在我有了一个Item和所有引用此Item的ItemStatusses,我需要创建一个新对象。每个ItemStatus都有一个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 ...
,因此您只需获取属于此ID的Status。
但是,您的问题是您有多个StatusId
引用相同的itemStatussesOfThisItem
,换句话说:它们具有相同的Status
值。
您可以首先获取属于该项目的状态,然后删除重复项。如果先删除重复的StatusId,然后获取具有此ID的Status,则效率更高。
继续加入群组:
StatusId
示例:
(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(),});
在参数resultSelector的开头,您有 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
:
- 项目[10]及其ItemStatusses [10,20] [10,21] [10,20]
- 项目[11]及其ItemStatusses [11,22] [11,22] [11,20]
- 项目[12]的项目状态为空
- 具有ItemStatusses [13,21] [13,21]的项目[13]
对于所有这些项目,您将创建一个具有两个属性的新对象:(item,itemStatussesOfThisItem)
和Id
。 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}
现在您具有唯一的StatusId,可以轻松地描述这些状态:
Statusses
结果:
- 状态为“好”,“不是”的项目ID 10
- 状态为“好”,“未知”的项目ID 11
- 没有任何状态的商品ID 12
- 状态为“ NotOk”的商品ID 13
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。