繁体   English   中英

一对一映射问题

[英]One-To-One Mapping issue

我的SQL理解是相当基础的,我来自NHibernate的世界,所以我对这个问题感到很困惑......

我有两节课:

public class UserProfile
{
    public UserProfile() { }

    [Key]
    public int UserId { get; set; }
    public string UserName { get; set; }
    public SerialNumber Serial { get; set; }
    // Other properties
}

public class SerialNumber
{
    public SerialNumber() 
    {
        // My code that creates a unique Code
    }

    [Key]
    public string Code { get; set; }
    public UserProfile User { get; set; }

    // Other Properties
}

我有这个

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Other modelBuilder stuff

    modelBuilder.Entity<UserProfile>()
        .HasOptional(s => s.Serial)
        .WithRequired(u => u.User);
}

运行Add-Migration我得到了这个:

public override void Up()
{
    DropForeignKey("dbo.UserProfile", "Serial_Code", "dbo.SerialNumbers");
    DropIndex("dbo.UserProfile", new[] { "Serial_Code" });
    RenameColumn(table: "dbo.SerialNumbers", name: "Serial_Code", newName: "User_UserId");
    AddForeignKey("dbo.SerialNumbers", "User_UserId", "dbo.UserProfile", "UserId");
    CreateIndex("dbo.SerialNumbers", "User_UserId");
}

public override void Down()
{
    // Inverse of above
}

运行Update-Database我收到一个错误: "Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong."

我可以通过Add-Migration生成的代码告诉我出错了,因为我的db表甚至没有名为"Serial_Code"

我需要Code作为我的Key因为EntityFramework没有选项强制列为Unique除非使其成为键。

如何将Serial作为UserProfile的可选属性,并将SerialNumber User添加到UserProfile时自动设置?

默认情况下,在一对一关系中,Entity Framework要求依赖项上的外键也是主键。 这可能是因为实体框架仅对主键设置了唯一约束(或者说,由于它是主键,因此存在唯一约束)。 在数据库的级别上,一对一不映射到关系的两侧,即在两个表上都没有创建外键。 当您考虑参照完整性如何工作时,这是有道理的:如果关系的一方被删除,则会导致另一方的数据库分离,导致一种无限循环。

因此,外键被添加到依赖项,在这种情况下,就像你在这里一样,这就是具有所需导航属性的结尾:你的SerialNumber模型。 这意味着要真正创建一对一而不是一对多, SerialNumber上的密钥需要是User_UserId (自动生成的外键列,因为您没有手动指定外键属性) )。 要以这种方式进行设置,您的模型将如下所示:

public class UserProfile
{
    [Key]
    public int UserId { get; set; }

    public SerialNumber Serial { get; set; }

    ...
}

public class SerialNumber
{
    [Key]
    [ForeignKey("User")]
    public int UserId { get; set; }

    public UserProfile User { get; set; }

    ...
}

或者使用Fluent API:

modelBuilder.Entity<SerialNumber>()
    .HasRequired(m => m.User)
    .WithOptional(m => m.Serial);

(您需要省略[Key]数据注释,以便EF可以创建外键,它们是表的主键。)

但是,这使您在Code属性上没有唯一约束。 您当然可以在表上手动设置此约束,或者如果您不使用自动迁移,则可以更改迁移以创建约束:

CreateIndex("dbo.SerialNumbers", "Code", unique: true);

这里的问题是实体框架不会为您处理唯一的验证。 因此,您需要在代码中手动维护完整性(即,尝试使用您要保存的Code查找SerialNumber ,并且只有在您从查询中得不到任何内容时才保存它)。

我知道,这是一种痛苦,但就目前而言,这就是你所能做的一切。 希望EF能够最终解决未来版本中的独特性问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM