C# 多对多关系问题+;实体框架6中的TPH固有性

C# 多对多关系问题+;实体框架6中的TPH固有性,c#,entity-framework,many-to-many,entity-framework-6,table-per-hierarchy,C#,Entity Framework,Many To Many,Entity Framework 6,Table Per Hierarchy,我在EF6中遇到了一个问题,尽管我相当肯定这适用于支持这种映射类型的早期版本。我恐怕我知道眼前问题的答案,但我希望我做错了什么,或者有比我现在介绍的更好的解决办法。为了清晰起见,所有的课程都被删掉了 所以我有 public abstract class SoftwareFirmware { public long Id { get; private set; } public ICollection<DeviceType> DeviceTypes { get; pri

我在EF6中遇到了一个问题,尽管我相当肯定这适用于支持这种映射类型的早期版本。我恐怕我知道眼前问题的答案,但我希望我做错了什么,或者有比我现在介绍的更好的解决办法。为了清晰起见,所有的课程都被删掉了

所以我有

public abstract class SoftwareFirmware
{
    public long Id { get; private set; }
    public ICollection<DeviceType> DeviceTypes { get; private set; } 

    public SoftwareFirmware()
    {
        DeviceTypes=new HashSet<DeviceType>();
    }
}

我使用每个层次结构的表继承,因此
软件
固件
存储在同一个表中,并带有一个鉴别器列。最后,我用

modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany(firmware=>firmware.DeviceTypes);
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany(sofware=>sofware.DeviceTypes);
它生成了这个模式-几乎完全是我想要的模式(忽略额外的属性):


但是,由于对
的无参数调用WithMany
只在一侧连接了导航属性,因此EF不会跟踪对
软件.devicetype
固件.devicetype
的更新,所以我回到了开始的地方。

这个问题听起来很熟悉。(查看我的电子邮件…是的,那是一年多以前的事了!)我让人给我发了一个示例,其中fluent api关系失败了。他们没有多对多,但我认为这是同样的问题。我花了很长时间研究它,并询问了Rowan Miller(团队成员),他说fluent api无法理解来自基类型的属性

i、 e.fluent API在查看AvailableSoftwareVersions或AvailableFirmwareVersions时无法看到DEVICETYPE属性。(我不能告诉你这是为什么。你可能认为它可以通过反射找到它,但可能它只是没有考虑到这个场景。)

这对我来说仍然没有意义,所以他进一步解释了(我会用你的类型更新他的解释,这有点混乱,因为你有额外的继承级别,而且东西的命名有点不一致……但是我

从概念上讲,这些类没有什么意义,因为DeviceType 可以有多个软件或固件…但反向导航属性为 在SoftwareFirmware上定义的。那么,当某些东西不是 固件或软件具有DeviceType?其相反配置为>DeviceType.AvailableSoftwareVersions 但那不行。即使用正确的方法把EF从图片中去掉 要对其建模,将使项目属性位于报告中

这就是EF5。如果我的记忆是正确的,并且是同一个问题,那么EF6可能没有改变。也许我们应该看看解决这个问题是否存在问题。然而,他的进一步解释表明,这不是一个错误,而是一种保护

(我要打电话给他,以验证我是否正确地推断出了这个问题的前一个问题)


在那封电子邮件中,Rowan还建议使用getter逻辑而不是导航属性作为解决方法。

这个问题听起来很熟悉。(查看我的电子邮件……是的,那是一年多以前的事了!)有人给我发送了一个fluent api关系失败的示例。他们没有多对多关系,但我认为这是同一个问题。我花了很长时间研究它,并询问了Rowan Miller(团队成员),他说fluent api无法理解来自基类型的属性

i、 e.fluent API在查看AvailableSoftwareVersions或AvailableFirmwareVersions时无法看到DEVICETYPE属性。(我无法告诉您原因。您可能认为它可以通过反射找到,但可能只是没有考虑到这种情况。)

这对我来说仍然没有意义,所以他进一步解释了(我会用你的类型更新他的解释,这有点混乱,因为你有额外的继承级别,而且东西的命名有点不一致……但是我

从概念上讲,这些类没有什么意义,因为DeviceType 可以有多个软件或固件…但反向导航属性为 在SoftwareFirmware上定义的。那么,当某些东西不是 固件或软件具有DeviceType?其相反配置为>DeviceType.AvailableSoftwareVersions 但那不行。即使用正确的方法把EF从图片中去掉 要对其建模,将使项目属性位于报告中

这就是EF5。如果我的记忆是正确的,并且是同一个问题,那么EF6可能没有改变。也许我们应该看看解决这个问题是否存在问题。然而,他的进一步解释表明,这不是一个错误,而是一种保护

(我要打电话给他,以验证我是否正确地推断出了这个问题的前一个问题)


在那封电子邮件中,Rowan还建议使用getter逻辑而不是导航属性作为解决方法。

问题是您只有一个SoftwareFirmware.DeviceTypes属性,但您试图将其作为两个独立关系的一部分使用。SoftwareFirmware.DeviceTypes不能同时是两个DeviceType.AvailableFirmwar的反向eVerions和DeviceType.AvailablesOfWarEverions

你试图建立的模型有点奇怪,因为你将它们视为不同的关系,但也不是。这里有两种选择

选项1:这是两个独立的关系

删除SoftwareFirmware.DeviceTypes并在固件和软件上添加DeviceTypes属性

这实际上是当您在SoftwareFirmware.DeviceTypes属性上设置Ignore并使用WithMany的空重载时所做的操作-这就是它工作的原因。您告诉EF有两种关系(一种是软件->设备类型,另一种是固件->设备类型)而且没有指向另一个方向的导航属性。因为您忽略了softwareffirmware.DeviceTypes,所以它不是您模型的一部分

选项2:这是一种关系
public class Firmware : SoftwareFirmware {}
public class Software : SoftwareFirmware {}
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany(firmware=>firmware.DeviceTypes);
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany(sofware=>sofware.DeviceTypes);
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableFirmwareVerions).WithMany();
modelBuilder.Entity<DeviceType>().HasMany(d => d.AvailableSoftwareVerions).WithMany();
modelBuilder.Entity<SoftwareFirmware>().Ignore(s => s.DeviceTypes);
public class DeviceType
{
    public long Id { get; set; }

    public virtual ICollection<SoftwareFirmware> AvailableVerions { get; private set; }

    public virtual IEnumerable<Firmware> AvailableFirmwareVerions
    {
        get
        {
            return this.AvailableVerions.OfType<Firmware>();
        }
    }

    public virtual IEnumerable<Software> AvailableSoftwareVerions
    {
        get
        {
            return this.AvailableVerions.OfType<Software>();
        }
    }

    public DeviceType()
    {
        AvailableVerions = new HashSet<SoftwareFirmware>();
    }
}