如何使用entity framework来声明一对一的关系4 Code First(POCO)

如何使用entity framework4代码优先(POCO)声明一对一的关系?

我发现这个问题(entity framework4中的一对一关系) ,但是这个答案引用的文章没有用(有一行代码是1-1关系,但没有提及如何定义它)。

你只是在寻找这样的东西?

public class User { public int Id { get; set; } public string Username { get; set; } public Profile Profile { get; set; } public int ProfileId { get; set; } } public class Profile { public int Id { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string PostalCode { get; set; } // etc... } public class UserMapping : EntityConfiguration<User> { public UserMapping() { this.HasKey(u => u.Id); this.Property(u => u.Username).HasMaxLength(32); // User has ONE profile. this.HasRequired(u => u.Profile); } } public class ProfileMapping : EntityConfiguration<Profile> { public ProfileMapping() { this.HasKey(p => p.Id); this.Property(p => p.FirstName).HasMaxLength(32); this.Property(p => p.LastName).HasMaxLength(32); this.Property(p => p.PostalCode).HasMaxLength(6); } } 

编辑 :是啊,我没有VS在我面前,但你需要在UserMapping而不是当前的HasRequired添加以下行,并添加一个ProfileId属性(而不是你添加的Profile_Id ):

 this.HasRequired(u => u.Profile).HasConstraint((u, p) => u.ProfileId == p.Id); 

我目前认为没有办法解决这个问题,但是我确定它会改变,因为我们只有CTP4。 如果我能说:

 this.HasRequired(u => u.Profile).WithSingle().Map( new StoreForeignKeyName("ProfileId")); 

这样我就不必包含一个ProfileId属性。 也许现在有一种解决方法,而且还是在凌晨,我才想到:)。

如果要包含“导航属性”,还请记住调用.Include("Profile")

三种方法:

A)声明两个导航属性的类彼此。 使用其主键上的ForeignKey属性标记其中一个表(从属表)。 EF从此推断1对1:

 public class AppUser { public int Id { get; set; } public string Username { get; set; } public OpenIdInfo OpenIdInfo { get; set; } } ​public class OpenIdInfo { [ForeignKey("AppUser")] public int Id { get; set; } public string OpenId { get; set; } public AppUser AppUser { get; set; } } 

http://weblogs.asp.net/manavi/archive/2011/05/01/associations-in-ef-4-1-code-first-part-5-one-to-one-foreign-key-associations。; ASPX

我没有使用virtual ,你也不应该。*

B)声明一个inheritance层次结构,其中明确声明了两个表名,从而得到Table-Per-Type和一个共享的主键。

 using System.ComponentModel.DataAnnotations; [Table("AppUser")] public class AppUser { public int Id { get; set; } public string Username { get; set; } public OpenIdInfo OpenIdInfo { get; set; } } [Table("AdminUser")] public class AdminUser : AppUser { public bool SuperAdmin { get; set; } } 

你会得到2个表格:一个用于AppUser,一个用于AdminUser。 AdminUser与AppUser是1:1并且是依赖的 – 意味着你可以删除一个AdminUser,但是如果你在AdminUser仍然指向它的时候删除了一个AppUser,你会得到一个约束违规错误。

C)EF中有两种中途一对一的方法:

Entity-Splitting ,你有一个Class,但是它存储在一个主表以及一个或多个一对一的相关表中。

表 – 分裂 ,对象的树平展成一张桌子。 例如,具有Address属性的类将Address对象的列(例如Address_City)展开为一个表。

* 如果您想延迟加载,您可以在任何EF Property或Collections上包含虚拟内容。 这可能会导致无限循环或加载整个数据库,如果您将具有延迟加载属性的对象传递给,例如,MVC JSON转换器或任何其他走过对象层次结构。 延迟加载总是同步完成,阻塞线程,没有任何通知。 总而言之,可以冻结代码,应用程序或服务器的方式很长。 避免在EF类上使用虚拟。 是的,互联网上有很多代码示例使用它。 不,你仍然不应该使用它。

 public class User { public int Id { get; set; } public string Username { get; set; } public virtual Profile Profile { get; set; } } public class Profile { public int Id { get; set; } public int UserID { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string PostalCode { get; set; } } 

添加虚拟configuration文件和用户ID,我认为应该让你在那里。

以下面的Student和StudentAddress实体为例。
使用DataAnnotationsconfiguration一对一或一对一的关系:

 public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual StudentAddress Address { get; set; } } public class StudentAddress { [ForeignKey("Student")] public int StudentAddressId { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string City { get; set; } public int Zipcode { get; set; } public string State { get; set; } public string Country { get; set; } public virtual Student Student { get; set; } } 

当StudentAddress实体不遵循约定时:

例如,如果StudentAddress实体不遵循PK的约定,即Id属性的名称不同,则还需要将其configuration为PK。 考虑以下具有属性名称StudentId而不是StudentAddressId的StudentAddress实体。

 public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual StudentAddress Address { get; set; } } public class StudentAddress { [Key, ForeignKey("Student")] public int StudentId { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string City { get; set; } public int Zipcode { get; set; } public string State { get; set; } public string Country { get; set; } public virtual Student Student { get; set; } } 

在上面的例子中,我们需要将StudentId属性configuration为Key以及ForeignKey。 这将使StudentAddress实体中的StudentId属性成为PK和FK。

使用Fluent APIconfigurationOne-to-Zero-or-One关系:
当Student和StudentAddress遵循以下约定时:Student和StudentAddress实体遵循PrimaryKey的默认代码优先约定。 所以,我们不需要configuration它们来定义它们的PrimaryKeys。 我们只需要configurationStudentAddressId应该是ForeignKey的StudentAddress实体。

以下示例使用Fluent API在Student和StudentAddress之间设置一对一或一个关系。

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Configure Student & StudentAddress entity modelBuilder.Entity<Student>() .HasOptional(s => s.Address) // Mark Address property optional in Student entity .WithRequired(ad => ad.Student); // mark Student property as required in StudentAddress entity. Cannot save StudentAddress without Student } 

在上例中,Student实体使用HasOptional()方法进行configuration,该方法指示Student实体中的StudentAddress导航属性是可选的(保存Student实体时不需要)。 然后,WithRequired()方法根据需要configurationStudentAddress实体并创buildStudentAddress的Student导航属性(保存StudentAddress实体时需要),当StudentAddress实体保存没有Student导航属性时,将引发exception。 这将使StudentAddressId作为ForeignKey也。

因此,您可以在不添加StudentAddress对象的情况下configuration两个实体之间的一对一关系,但StudentAddress实体不能在不附加Student实体的对象的情况下保存。 这使得一个需要。

当StudentAddress实体不遵循约定时:
现在我们来看一个StudentAddress实体的例子,它不遵循主键约定,即具有与Id不同的Id属性名称。 考虑以下Student和StudentAddress实体。

 public class Student { public Student() { } public int StudentId { get; set; } public string StudentName { get; set; } public virtual StudentAddress Address { get; set; } } public class StudentAddress { public int StudentId { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string City { get; set; } public int Zipcode { get; set; } public string State { get; set; } public string Country { get; set; } public virtual Student Student { get; set; } } 

所以现在,我们需要为StudentAddress的PrimaryKey以及ForeignKeyconfigurationStudentAddress的StudentId属性,如下所示。

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Configure StudentId as PK for StudentAddress modelBuilder.Entity<StudentAddress>() .HasKey(e => e.StudentId); // Configure StudentId as FK for StudentAddress modelBuilder.Entity<Student>() .HasOptional(s => s.Address) .WithRequired(ad => ad.Student); } 

使用Fluent APIconfiguration一对一关系:
我们可以使用需要两端的Fluent API来configuration实体之间的一对一关系,这意味着学生实体对象必须包含StudentAddress实体对象,并且StudentAddress实体必须包含Student实体对象才能保存它。

注意:在MS SQL Server中,技术上不可能build立一对一的关系。 它将永远是一个零或一个。 EF在不在数据库中的实体之间形成一对一的关系。

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { // Configure StudentId as PK for StudentAddress modelBuilder.Entity<StudentAddress>() .HasKey(e => e.StudentId); // Configure StudentId as FK for StudentAddress modelBuilder.Entity<Student>() .HasRequired(s => s.Address) .WithRequiredPrincipal(ad => ad.Student); } 

在上面的例子中,modelBuilder.Entity()。HasRequired(s => s.Address)使得StudentAddress的Address属性是必需的。 .WithRequiredPrincipal(ad => ad.Student)根据需要创buildStudentAddress实体的Student属性。 因此它configuration所需的两端。 所以,现在,当您尝试保存没有地址的Student实体或没有Student的StudentAddress实体时,它会抛出一个exception。

参考: http : //www.entityframeworktutorial.net/code-first/configure-one-to-one-relationship-in-code-first.aspx