2013-04-04 110 views
1

我的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除了牛逼o让它成为关键。

如何使Serial是的UserProfileUser一个可选属性在SerialNumber当它加入到UserProfile被自动设置?

回答

4

默认情况下,在一对一关系中,实体框架要求依赖项上的外键也是主键。这很可能是由于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; } 

    ... 
} 

或用流利的API:

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

(你会需要离开关[Key]数据注解,使EF可以使外键,他们为表的主键。)

这使得您无需您Code属性的唯一约束,虽然。你当然也可以手动设置你的桌子上此约束,或者如果你不使用自动迁移,你可以改变你的迁移来建立约束:

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

这里的问题是,实体框架不会处理独特验证你。因此,您需要在代码中手动维护完整性(例如,尝试使用您要保存的Code来查找SerialNumber,并且只有在您没有从查询中得到任何回复时才保存它)。

我知道这是一种痛苦,但现在,这就是你所能做到的。希望EF能够在未来的版本中解决唯一性问题。

+0

谢谢你这么详细的解释 – 2013-04-04 02:05:30