你的问题和我建议的问题之间的主要区别复制 https://stackoverflow.com/a/5441569/861716是你的ForeignKey
属性不引用 -
在您的情况下,引用是从一个原始属性到另一种类型的另一个原始属性。还有,小细节,VirtualMachine.Datetime
应该是财产,而不是成员。但我不得不承认,“重复”并不包括你的情况。
因此,让我们尝试将其变成如何在 Entity Framework 6 中处理这种情况的全面答案。我将使用抽象模型来解释各种选项:
public class Parent
{
public int Id1 { get; set; } // Key
public int Id2 { get; set; } // Key
public string Name { get; set; }
public virtual List<Child> Children { get; set; }
}
public class Child
{
public int Id1 { get; set; } // Key
public int Id2 { get; set; } // Key
public int Id3 { get; set; } // Key
public string Name { get; set; }
public virtual Parent Parent { get; set; }
}
有三个选项可用于设置映射。
Option 1
数据注释,ForeignKey
属性:
public class Parent
{
[Key]
[Column(Order = 1)]
public int Id1 { get; set; }
[Key]
[Column(Order = 2)]
public int Id2 { get; set; }
public string Name { get; set; }
public virtual List<Child> Children { get; set; }
}
public class Child
{
[Key]
[Column(Order = 0)]
public int Id1 { get; set; }
[Key]
[Column(Order = 1)]
public int Id2 { get; set; }
[Key]
[Column(Order = 2)]
public int Id3 { get; set; }
public string Name { get; set; }
[ForeignKey("Id1,Id2")]
public virtual Parent Parent { get; set; }
}
如您所见,这里ForeignKey
属性是指从导航属性到原始属性。此外,列顺序中的绝对数字并不重要,重要的是它们的顺序。
Option 2
数据注释,InverseProperty
属性:
public class Parent
{
[Key]
[Column(Order = 1)]
public int Id1 { get; set; }
[Key]
[Column(Order = 2)]
public int Id2 { get; set; }
public string Name { get; set; }
public virtual List<Child> Children { get; set; }
}
public class Child
{
[Key]
[Column(Order = 0)]
[InverseProperty("Children")]
public int Id1 { get; set; }
[Key]
[Column(Order = 1)]
[InverseProperty("Children")]
public int Id2 { get; set; }
[Key]
[Column(Order = 2)]
public int Id3 { get; set; }
public string Name { get; set; }
public virtual Parent Parent { get; set; }
}
InverseProperty
从关系一端的类型中的一个或多个属性指向关系另一端的类型中的导航属性。实现相同映射的另一种方法是应用[InverseProperty("Parent")]
的两个关键属性Parent
.
Option 3
流畅的映射:
modelBuilder.Entity<Parent>().HasKey(p => new { p.Id1, p.Id2 });
modelBuilder.Entity<Child>().HasKey(p => new { p.Id1, p.Id2, p.Id3 });
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithRequired(c => c.Parent)
.HasForeignKey(c => new { c.Id1, c.Id2 });
正如评论中所说,流畅的映射比数据注释更不容易出错。数据注释提供了太多的选项来配置映射,并且并不总是很容易看出哪些部分是连接的。这就是为什么我最喜欢流畅的映射。
实体框架核心
在 EF-core(当前版本 3.1.6)中,复合主键无法通过数据注释建模。它抛出一个运行时异常:
实体类型“Parent”具有使用数据注释定义的复合主键。要设置复合主键,请使用 Fluent API。
所以对于 EF-core 只有选项 3 是可行的。映射几乎相同:
modelBuilder.Entity<Parent>().HasKey(p => new { p.Id1, p.Id2 });
modelBuilder.Entity<Child>().HasKey(p => new { p.Id1, p.Id2, p.Id3 });
modelBuilder.Entity<Parent>()
.HasMany(p => p.Children)
.WithOne(c => c.Parent) // Different here
.HasForeignKey(c => new { c.Id1, c.Id2 });