Entity Framework 6.0 code first 一对一关系(one to one) 详解

欢迎转载,转载请注明出处 http://www.cnblogs.com/youyoubaishu/p/3866697.html

最近研究了一下 Entity Framework一对一关系的mapping,略有收获,在此进行一些总结,希望对各位读者也有所帮助:

有两点非常重要,需要大家注意:

1. Entity Framework code first convention里,建议如果使用一对一关系,需要共享主键,即一张表使用另一张表的主键做为自己的主键。

2. 如果不共享主键,是不是有办法做呢?答案是有的,之后我会介绍,但是个人不建议使用,可能有未知错误,而且个人以为没有必要。

下面使用一个例子来说明一对一关系:

用例逻辑: 一个person类,一个user类,user类里有登录信息。每个user一定是一个person,反之一个person不一定有一个登录帐号。

共享主键的方法

直接上代码, 先是model:

public class Person
{
    public int PersonId { get; set; }

    public string LastName { get; set; }
    public string GivenName { get; set; }
    public string MiddleName { get; set; }
    public string Gender { get; set; }

    public int UserId { get; set; }//这里是Foreign Key

    public virtual User UserAccount { get; set; }//这里是Navigation Property
}
public class User
{
    public int PersonId { get; set; }

    public string UserName { get; set; }
public string Password { get; set; } public Person Person { get; set; } }

注意,这里User没有UserId

接下来上mapping:

public PersonMap()
{
    this.ToTable("PersonTable");
    this.HasKey(t => t.PersonId);

    this.Property(t => t.PersonId).HasColumnName("PersonId");
    this.Property(t => t.Gender).HasColumnName("Gender").IsRequired();
    this.Property(t => t.LastName).HasColumnName("LastName").IsRequired();
    this.Property(t => t.GivenName).HasColumnName("GivenName").IsRequired();

    this.Property(t => t.MiddleName).HasColumnName("MiddleName");//默认是IsOptional()
}
public UserMap()
{
    this.ToTable("UserTable");
    this.HasKey(t => t.PersonId);

    this.Property(t => t.UserName).HasColumnName("UserName");
    this.Property(t => t.Password).HasColumnName("Password");

    this.HasRequired(t => t.Person)
        .WithOptional(t => t.UserAccount);
}

这样生成的表,关系就是正确的。

 

不共享主键的方法(不推荐)

Person类一样,唯一不一样的是User类

Model:

public class User
{
    public UserId { get; set; }//主键

    public string UserName { get; set; }
public string Password { get; set; } public Person Person { get; set; } }

Mapping:

public UserMap()
{
    this.ToTable("UserTable");
    this.HasKey(t => t.UserId);

    this.Property(t => t.UserName).HasColumnName("UserName");
    this.Property(t => t.Password).HasColumnName("Password");

    this.HasRequired(t => t.Person)
        .WithOptional(t => t.UserAccount)
        .Map(t=>t.MapKey("PersonId"));;
}

这样的方法,我也使用过,貌似没有出问题,但是,有3个原因我不建议使用:

1. 非标准方法,不能保证多重关系级联时不产生问题。

2. 无法使用PersonId property设置关系,而必须使用DbContext中的实体,做为参数漫天传不是一个很好的做法。一旦DbContext刷新,而没有重新刷新实体,会导致entity framwork报错。

3. 根据官方的文档,有navigation property时建议在实体中保留foreign key。

 

一些错误的做法(有时候也能用,但是本质上是错误的)

有一些地方,比如教你怎么使用早期entity frame版本的blog,可能会推荐你使用HasMany来mapping一对一关系,我个人是不推荐的(虽然HasMany之后可以使用Fluent API来map外键)。这是一种取巧的方法,使用一对多的方式代替了一对一,但是从本质上破坏了一对一关系的逻辑。处于代码可读和维护的角度来说,不推荐这样使用。我使用过一对多关系代替一对一使用,途中遇到过一些奇怪的问题,这里不一一阐述(其实是我没有一一记录)。

 

文中若有如有不妥之处,敬请批评指正。

 

参考文档:

【1】http://stackoverflow.com/questions/1761362/entity-framework-one-to-one-mapping-issues

【2】http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-3-shared-primary-key-associations 这篇文章里告诉了你使用共享主键方法mapping一对一关系的方法,以及“弊端”,个人觉得弊端说的不是特别有道理。但是全文对一对一关系解释的相当仔细,值得参考。

【3】http://weblogs.asp.net/manavi/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations 这篇文章和【2】出自同一个博客,这里列出来,是因为说的很好。这里使用了HasMany来mapping“一对一关系”,但是仔细看一下,你会发现,这里在本质上其实是一对多关系的,因为需求改变了,导致数据库设计从一对一升级成为了一对多,所以这样的方法反而是正确可取的。

posted @ 2014-07-24 22:51  优游柏树  阅读(2192)  评论(0编辑  收藏  举报