将复合外键映射到复合主键,其中外键也是主键 [英] Mapping composite foreign key to composite primary key where the foreign key is also a primary key

查看:83
本文介绍了将复合外键映射到复合主键,其中外键也是主键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将VM_hostname,datetime和name属性设置为磁盘类的组合键.同时,磁盘类的VM_hostname和日期时间应参考 VirtualMachine 类的VM_hostname和日期时间(即外键).

I want to make VM_hostname,datetime and name properties as a composite Key for Disk class . At the same time VM_hostname and datetime of Disk class should refer to VM_hostname and datetime of VirtualMachine class (ie Foreign keys) .

我这样做了,但是它给了我这个例外:类型'WebJob1.Historical.Disk'上属性'datetime'上的ForeignKeyAttribute无效.在依赖类型"WebJob1.Historical.Disk"上找不到导航属性"Datetime".名称值应为有效的导航属性名称

I did this but it gives me this exception : The ForeignKeyAttribute on property 'datetime' on type 'WebJob1.Historical.Disk' is not valid. The navigation property 'Datetime' was not found on the dependent type 'WebJob1.Historical.Disk'. The Name value should be a valid navigation property name

有人知道吗?另外,请注意我正在使用数据注释.

Anyone have a clue ? Also, please note that im using Data Annotation.

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; }


}

推荐答案

您的问题与我建议的问题之间的主要区别为重复是您的 ForeignKey 属性没有引用-

The main difference between your question and the one I suggested as duplicate is that your ForeignKey attributes don't refer -

  • 从原始属性到导航属性
  • 从导航属性到原始属性

在您的情况下,引用是从原始属性到另一种其他类型的原始属性的.另外, VirtualMachine.Datetime 应该很少是属性,而不是成员.但我必须承认,重复"没有涵盖您的情况.

In your case, the reference is from a primitive property to another primitive property, in another type. Also, little detail, VirtualMachine.Datetime should be a property, not a member. But I have to admit that the "duplicate" didn't cover your case.

因此,让我们尝试将其作为一个全面的答案,说明如何在Entity Framework 6中处理这种情况.我将使用抽象模型来解释各种选项:

So let's try to make this into a comprehensive answer how to handle this situation in Entity Framework 6. I'll use an abstracted model to explain the various options:

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; }
} 

有三种设置映射的选项.

There are three options to setup the mappings.

数据注释, 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 属性从导航属性引用到原始属性.另外,列顺序中的绝对数字无关紧要,仅取决于它们的顺序.

As you see, here the ForeignKey attribute refers from a navigation property to primitive properties. Also, the absolute numbers in the column order don't matter, only their sequence.

数据注释, 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")]] .

InverseProperty points from one or more properties in a type at one end of a relationship to a navigation property in the type on the other end of the relationship. Another way to achieve the same mapping is to apply [InverseProperty("Parent")] on both key properties of Parent.

流动剂映射:

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 });

正如评论中所说,流利的映射比数据注释更不容易出错.数据注释提供了太多的选项来配置映射,而且并不总是很容易看到连接的部分.这就是为什么我最喜欢流利的映射的原因.

As said in the comments, fluent mapping is less error-prone than data annotations. Data annotations offer too many options to configure mappings and it's not always easy to see which parts are connected. That's why fluent mapping is my favorite.

在EF-core(当前版本3.1.6)中,复合主键无法通过数据注释建模.它将引发运行时异常:

In EF-core (current version 3.1.6) composite primary keys can't be modeled by data annotations. It throws a run-time exception:

实体类型父母"具有使用数据注释定义的复合主键.要设置复合主键,请使用fluent API.

Entity type 'Parent' has composite primary key defined with data annotations. To set composite primary key, use fluent API.

因此,对于EF-core,仅选项3是可行的.映射几乎相同:

So for EF-core only option 3 is feasible. The mapping is almost identical:

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 });

这篇关于将复合外键映射到复合主键,其中外键也是主键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆