简体   繁体   English

一对一映射问题

[英]One-To-One Mapping issue

My SQL understanding is fairly basic and I come from a world of NHibernate so I'm fairly puzzled by this issue... 我的SQL理解是相当基础的,我来自NHibernate的世界,所以我对这个问题感到很困惑......

I have two classes: 我有两节课:

public class UserProfile
{
    public UserProfile() { }

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

and

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
}

I have this 我有这个

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

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

After I run Add-Migration I get this: 运行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
}

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

I can tell by the code generated by Add-Migration that something is wrong as my db table doesn't even have a column by the name of "Serial_Code" 我可以通过Add-Migration生成的代码告诉我出错了,因为我的db表甚至没有名为"Serial_Code"

I need Code to be my Key as EntityFramework doesn't have an option to enforce a column to be Unique except to make it a key. 我需要Code作为我的Key因为EntityFramework没有选项强制列为Unique除非使其成为键。

How do I make Serial to be an optional property of UserProfile and User in SerialNumber to be automatically set when it's added to UserProfile ? 如何将Serial作为UserProfile的可选属性,并将SerialNumber User添加到UserProfile时自动设置?

By default, in one-to-one relationships, Entity Framework requires the foreign key on the dependent to also be the primary key. 默认情况下,在一对一关系中,Entity Framework要求依赖项上的外键也是主键。 This is likely due to the fact that Entity Framework only sets unique constraints on primary keys (or rather the unique constraint is there by virtue of it being a primary key). 这可能是因为实体框架仅对主键设置了唯一约束(或者说,由于它是主键,因此存在唯一约束)。 On the level of the database, the one-to-one is not mapped onto both sides of the relationship, ie there's not a foreign key created on both tables. 在数据库的级别上,一对一不映射到关系的两侧,即在两个表上都没有创建外键。 This makes sense when you think about how referential integrity works: if one side of the relationship is removed, it would cause database disintegrity for the other side, resulting in a sort of endless loop. 当您考虑参照完整性如何工作时,这是有道理的:如果关系的一方被删除,则会导致另一方的数据库分离,导致一种无限循环。

So, the foreign key is added to the dependent, which in the case of a one-to-zero-to-one like you have here is the end with the required navigation property: your SerialNumber model. 因此,外键被添加到依赖项,在这种情况下,就像你在这里一样,这就是具有所需导航属性的结尾:你的SerialNumber模型。 That means that to truly create a one-to-one and not a one-to-many, your key on SerialNumber would need to be User_UserId (the auto-generated foreign key column, since you didn't manually specify a foreign key property). 这意味着要真正创建一对一而不是一对多, SerialNumber上的密钥需要是User_UserId (自动生成的外键列,因为您没有手动指定外键属性) )。 To set it up this way, your models would look like: 要以这种方式进行设置,您的模型将如下所示:

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

    ...
}

Or with Fluent API: 或者使用Fluent API:

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

(You would need to leave off the [Key] data annotation, so that EF can make the foreign key, they primary key for the table.) (您需要省略[Key]数据注释,以便EF可以创建外键,它们是表的主键。)

That leaves you without a unique constraint on your Code property, though. 但是,这使您在Code属性上没有唯一约束。 You can of course manually set this constraint on your table, or if you're not using automatic migrations, you can alter your migration to create the constraint: 您当然可以在表上手动设置此约束,或者如果您不使用自动迁移,则可以更改迁移以创建约束:

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

The problem here is that Entity Framework will not handle unique validation for you. 这里的问题是实体框架不会为您处理唯一的验证。 So, you'll need to maintain integrity manually within your code (ie, try to lookup a SerialNumber with the Code you're about to save, and only save it if you don't get anything back from the query). 因此,您需要在代码中手动维护完整性(即,尝试使用您要保存的Code查找SerialNumber ,并且只有在您从查询中得不到任何内容时才保存它)。

It's kind of a pain, I know, but for the moment, that's all you can do. 我知道,这是一种痛苦,但就目前而言,这就是你所能做的一切。 Hopefully, EF will finally address uniqueness in a future release. 希望EF能够最终解决未来版本中的独特性问题。

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

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