将复合外键映射到复合主键,其中外键也是主键
Mapping composite foreign key to composite primary key where the foreign key is also a primary key
我想将 VM_hostname、日期时间和名称属性作为 Disk class 的复合键。同时VM_hostname和Disk class的datetime应该参考VM_hostname和VirtualMachine的datetime class(即外键)。
我这样做了,但它给了我这个例外:
'WebJob1.Historical.Disk' 类型 属性 'datetime' 上的 ForeignKeyAttribute 无效。在依赖类型 'WebJob1.Historical.Disk' 上找不到导航 属性 'Datetime'。名称值应该是有效的导航 属性 名称
有人知道吗?另外,请注意我使用的是数据注释。
public class VirtualMachine
{
[Key]
[Column(Order = 0)]
public string VM_Hostname { get; set; }
[Key]
[Column(Order = 1)]
public DateTime Datetime;
public virtual List<Disk> disks { get; set; }
}
public class Disk
{
[Key,ForeignKey("VirtualMachine"),Column(Order = 0)]
public string VM_hostname { get; set; }
[Key,ForeignKey("Datetime"), Column(Order = 1)]
public DateTime datetime { get; set; }
[Key, Column(Order = 2)]
public string name { get; set; }
public virtual VirtualMachine VirtualMachine{ get; set; }
}
你的问题和我建议的 duplicate 之间的主要区别是你的 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; }
}
设置映射有三个选项。
选项 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
属性指的是从导航 属性 到原始属性。此外,列顺序中的绝对数字无关紧要,重要的是它们的顺序。
选项 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
从关系一端类型中的一个或多个属性指向关系另一端类型中的导航 属性。实现相同映射的另一种方法是在 Parent
.
的两个关键属性上应用 [InverseProperty("Parent")]
选项 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 });
正如评论所说,流畅的映射比数据注释更不容易出错。数据注释提供了太多配置映射的选项,并且并不总是很容易看出哪些部分是连接的。这就是为什么流利的映射是我的最爱。
Entity Framework核心
在 EF-core(当前版本 3.1.6)中,复合主键无法通过数据注释建模。它抛出 运行 次异常:
Entity type 'Parent' has composite primary key defined with data annotations. To set composite primary key, use 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 });
我想将 VM_hostname、日期时间和名称属性作为 Disk class 的复合键。同时VM_hostname和Disk class的datetime应该参考VM_hostname和VirtualMachine的datetime class(即外键)。
我这样做了,但它给了我这个例外: 'WebJob1.Historical.Disk' 类型 属性 'datetime' 上的 ForeignKeyAttribute 无效。在依赖类型 'WebJob1.Historical.Disk' 上找不到导航 属性 'Datetime'。名称值应该是有效的导航 属性 名称
有人知道吗?另外,请注意我使用的是数据注释。
public class VirtualMachine
{
[Key]
[Column(Order = 0)]
public string VM_Hostname { get; set; }
[Key]
[Column(Order = 1)]
public DateTime Datetime;
public virtual List<Disk> disks { get; set; }
}
public class Disk
{
[Key,ForeignKey("VirtualMachine"),Column(Order = 0)]
public string VM_hostname { get; set; }
[Key,ForeignKey("Datetime"), Column(Order = 1)]
public DateTime datetime { get; set; }
[Key, Column(Order = 2)]
public string name { get; set; }
public virtual VirtualMachine VirtualMachine{ get; set; }
}
你的问题和我建议的 duplicate 之间的主要区别是你的 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; }
}
设置映射有三个选项。
选项 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
属性指的是从导航 属性 到原始属性。此外,列顺序中的绝对数字无关紧要,重要的是它们的顺序。
选项 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
从关系一端类型中的一个或多个属性指向关系另一端类型中的导航 属性。实现相同映射的另一种方法是在 Parent
.
[InverseProperty("Parent")]
选项 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 });
正如评论所说,流畅的映射比数据注释更不容易出错。数据注释提供了太多配置映射的选项,并且并不总是很容易看出哪些部分是连接的。这就是为什么流利的映射是我的最爱。
Entity Framework核心
在 EF-core(当前版本 3.1.6)中,复合主键无法通过数据注释建模。它抛出 运行 次异常:
Entity type 'Parent' has composite primary key defined with data annotations. To set composite primary key, use 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 });