EF Core 过滤掉多对多关系中的重复实体

Posted

技术标签:

【中文标题】EF Core 过滤掉多对多关系中的重复实体【英文标题】:EF Core filtering out duplicate entities in many-to-many relationship 【发布时间】:2021-06-10 02:20:10 【问题描述】:

我遇到了一个问题,即实体框架核心 5 会忽略多对多关系中的重复条目。我的“设备”可以有任意数量的“传感器”(包括多个相同的传感器)。如果我尝试将 2 个相同的 Sensor 添加到设备中,EF 只会插入 1 个。如果我将 2 个相同的 Sensor 直接添加到 DeviceSensorRelation 表中,EF 只会在 Device.Sensors 列表中显示其中一个。

我运行 SQL Server Profiler 来检查正在运行的查询,它确实返回了 EF 未显示的所有条目。这是 EF Core 的限制,还是我缺少配置或其他什么? (我假设它注意到重复的 Sensor.Id 作为它的主键,只是没有意义,因为它们之间有一个表)

我的表结构如下:

CREATE TABLE [Hardware].[Device]
(
    [Id] [int] IDENTITY(1,1) NOT NULL, --PK
    [Name] [varchar](200) NOT NULL,
    [BuildDate] [date] NOT NULL
)

CREATE TABLE [Hardware].[Sensor]
(
    [Id] [int] IDENTITY(1,1) NOT NULL, --PK
    [Name] [varchar](200) NOT NULL,
    [Cost] [money] NOT NULL
)

CREATE TABLE [Hardware].[DeviceSensorRelation]
(
    [Id] [int] IDENTITY(1,1) NOT NULL, --PK
    [DeviceId] [int] NOT NULL, --FK to Device.Id table
    [SensorId] [int] NOT NULL --FK to Sensor.Id table
)

这些是 EF Core 实体:

public class Device

    public int Id  get; 
    public string Name  get; private set; 
    public DateTime BuildDate  get; private set; 

    private List<Sensor> sensors = new List<Sensor>();
    public IReadOnlyCollection<Sensor> Sensors => this.sensors;


public class Sensor

    public int Id  get; 
    public string Name  get; private set; 
    public decimal Cost  get; private set; 

    private List<Device> devices = new List<Device>();
    public IReadOnlyCollection<Device> Devices => this.devices;

这是在设备实体配置中设置关系的代码:

builder.HasMany(x => x.Sensors)
       .WithMany(x => x.Devices)
       .UsingEntity(b =>
       
           b.ToTable("DeviceSensorRelation", "Hardware");
           b.Property<int>("Id").UseIdentityColumn();
           b.Property<int>("DeviceId");
           b.Property<int>("SensorId");
           b.HasKey("Id");
       )

【问题讨论】:

您的查询是什么?你有没有尝试过将列表更改为收藏? EF Core 肯定存在一些问题。请在他们的 GitHub 问题跟踪器中检查/报告它github.com/dotnet/efcore/issues @zolfaghari 使用集合而不是列表的结果相同(它正在填充但删除重复项)。查询是指 sql 还是 linq 调用? 我想知道多次添加相同的传感器 record 是否有意义。实际上,您可能没有连接两次相同的传感器object,而是连接第二个相同type 的传感器对象。如果是这样,这两个传感器对象也需要在数据库中进行区分。每个传感器对象都应该有自己的记录。如果不是,如果一个物理传感器实际上两次连接到一个设备,那么这应该是连接记录DeviceSensorRelation 的属性,类似于NumberOfConnections 【参考方案1】:

我认为 EF 核心行为正确,请记住 EF 核心是数据库上的抽象,即使有 2 条记录 EF 核心只考虑“关系”。 连接表中的一条记录满足了说明两个实体是否相关所需的信息,第二条没有提供有关“实体已链接?”问题的更多信息。

您想存储和检索更多信息,您想知道传感器与设备“相关”的次数。 在这种情况下,我建议使用具有有效负载关系的多对多,并在连接实体中添加一个额外的列来存储额外信息,这可以是任何东西(由您来填充此信息):在这种情况下TypeOfDevice 和 TypeOfSensor 之间存在关系的次数。我用这些名称提到了您的实体,以关注这样一个事实,即简单的多对多将更适合将具有唯一序列号(唯一)的“具体”设备链接到具有唯一序列号的“具体”传感器。

如果在获取实体后尝试删除链接,会发生什么情况会很有趣,这 2 条记录是否都被删除?但仔细想想,我认为在 deviceId 和 sensorId 列的连接表上进行 pk 是个好主意(因为多对多的性质),所以这种情况永远不会发生。

【讨论】:

以上是关于EF Core 过滤掉多对多关系中的重复实体的主要内容,如果未能解决你的问题,请参考以下文章

EF Core 多对多关系

如何过滤 EF Core 中的多对多联接

使用流利的 api EF Core 5 的多对多关系

定义引用同一个表的多对多关系(EF7/core)

如何直接填充由 EF Core 生成的多对多关系连接表?

销售车中的 EF Core 多对多唯一键关系问题