如何创建一个具有复合键的表,其中每个成员都是其他表的外键成员

本文关键字:成员 其他 复合 创建 何创建 一个 | 更新日期: 2023-09-27 18:23:55

我(第一次)尝试在MVC项目上首先使用注释编写代码。

我创建了以下POCO。

[Table("Customers")]
public partial class Customer
{
    public int Id { get; set; }
    [Required]
    [DisplayName("First Name")]
    public string FirstName { get; set; }
    [DisplayName("Last Name")]
    [Required]
    public string LastName { get; set; }
    //other properties...
 }
[Table("Vehicles")]
public partial class Vehicle
{
    [Required]
    public int Id { get; set; }
    [Required]
    public int CustomerId { get; set; }
    [Required]
    public string Make { get; set; }
    [Required]
    public string Model { get; set; }
    [Required]
    public string Year { get; set; }
    //other fields
    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
}

[Table("CustomerAppointments")]
public partial class CustomerAppointment
{
    [Key,Column(Order=0)]
    public int CustomerId { get; set; }
    [Key,Column(Order=1)]
    public int VehicleId { get; set; }
    public DateTime? AppointmentDate { get; set; }
    public DateTime? AppointmentTime { get; set; }
    public string AvailableDays { get; set; }
    //other fields
    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
    [ForeignKey("VehicleId")]
    public virtual Vehicle Vehicle { get; set; }
}

我认为我在这里的意图相当明显。我有客户。这些客户有车辆。我想创建一个表CustomerAppointments,其中一个客户和一个客户的车辆被安排进行服务。

为了记录在案,这并不是整个模型,为了这个问题的目的已经简化了。

我正在使用MvcScaffolding来构建EF项目和视图。

一切都会编译,但当我试图导航到Customers页面(实际上是一个没有提到的引用客户的类)时,我会收到以下错误。。。

Introducing FOREIGN KEY constraint 'FK_dbo.CustomerAppointments_dbo.Vehicles_VehicleId' on table 'CustomerAppointments' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

我尝试过不同的注释,甚至尝试过使用像这样流畅的API。。。

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<CustomerAppointment>()
        .HasRequired(ca => ca.Customer)
        .WithRequiredPrincipal()
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<CustomerAppointment>()
        .HasRequired(ca => ca.Vehicle)
        .WithRequiredPrincipal()
        .WillCascadeOnDelete(false);
}

但我无法让它发挥作用。我已经阅读了我能在谷歌和SO上找到的每一个样本,但都无济于事。

PS。。。如果这只适用于Annotations,那将是我的首选。

如何创建一个具有复合键的表,其中每个成员都是其他表的外键成员

当删除Customer时,您的模型有两条从CustomerCustomerAppointment的级联删除路径:

  • Customer->Vehicle->CustomerAppointment
  • Customer->CustomerAppointment

这在SQL Server中是不允许的,并导致异常。您需要对这三个子路径中的至少一个子路径禁用级联删除,这只有使用Fluent API才能实现。例如Customer->Vehicle路径:

modelBuilder.Entity<Vehicle>()
    .HasRequired(v => v.Customer)
    .WithMany()
    .HasForeignKey(v => v.CustomerId)
    .WillCascadeOnDelete(false);

您还可以将CustomerId设为null,以具有可选关系,在这种情况下,EF将默认禁用级联删除。但是,将必需关系更改为可选关系表示业务规则发生了变化,我不会仅仅为了避免Fluent API而这样做。

BTW:CustomerAppointment应该有一个复合主键,这真的正确吗?这意味着,拥有特定车辆的特定客户只能预约一次服务。同一客户/车辆组合在不同的预约日期不能有很多预约吗?如果是,则应该为CustomerAppointmentCustomerId提供一个单独的密钥,而VehicleId将只是外键,而不是主键的一部分。

似乎最好使用数据库优先的方法,然后使用ado enity数据模型生成模型。

按照惯例,级联删除是通过在模型中引入实际外键来处理的。如果使用不可为null的外键,则需要将其删除。使用可为null的外键将其关闭。

通过将外键设为null,将类更改为以下内容:

[Table("CustomerAppointments")]
public partial class CustomerAppointment
{
    [Key,Column(Order=0)]
    public int? CustomerId { get; set; }
    [Key,Column(Order=1)]
    public int? VehicleId { get; set; }
    public DateTime? AppointmentDate { get; set; }
    public DateTime? AppointmentTime { get; set; }
    public string AvailableDays { get; set; }
    //other fields
    [ForeignKey("CustomerId")]
    public virtual Customer Customer { get; set; }
    [ForeignKey("VehicleId")]
    public virtual Vehicle Vehicle { get; set; }
}

记住还要删除流畅映射。

发件人http://msdn.microsoft.com/en-US/data/jj679962

如果依赖实体上的外键不可为null,则Code首先对关系设置级联删除。如果依赖实体可以为null,Code First不设置级联删除关于关系,并且当主体被删除时,外键将设置为null。