使用 EF4.1 Fluent API 将具有导航属性的实体拆分为两个表

Posted

技术标签:

【中文标题】使用 EF4.1 Fluent API 将具有导航属性的实体拆分为两个表【英文标题】:Splitting an Entity with navigational property into two tables using EF4.1 Fluent API 【发布时间】:2011-07-06 20:23:32 【问题描述】:

我有一个用户表和一个用户配置文件表。一个用户有零个或只有一个用户配置文件。 (即一对一的关系)有人可以帮助我使用 EF4.1 fluent API 将用户实体映射到用户和用户配置文件表。下面是表格的详细信息。用户和 AuthProvider 也有一对多的关系。

// 1. Users Table has the columns(UserId(PK), UserName, Email, AuthProviderId(FK))
// 2. UserProfiles Table has columns(UserId(PK/FK), FirstName, MiddleName,LastName)
// 3. AuthProvider Table has columns (AuthProviderId(PK), AuthName)

    public class User 
        public User() 
          Id = Guid.NewGuid();
        
        public virtual Guid Id  get; private set; 

        public virtual string Username  get; set; 
        public virtual string Email  get; set; 
        public virtual AuthProvider AuthProvider  get; set; 

        public virtual string FirstName  get; set; 
        public virtual string MiddleName  get; set; 
        public virtual string LastName  get; set; 
      

    public class AuthProvider 
        public AuthProvider() 
          Id = Guid.NewGuid();
        
        public virtual Guid Id  get; private set; 
        public virtual string Name  get; set;    
        public virtual ICollection<User> Users  get; set; 
      

    // This is the Mappings
     public class UserConfiguration : EntityTypeConfiguration<User> 
        public UserConfiguration() 
          HasKey(x => x.Id).Property(x => x.Id).HasColumnName("UserId").IsRequired();
          Property(x => x.Username).HasColumnName("Username").IsRequired();
          Property(x => x.Email).HasColumnName("Email").IsRequired();

          Property(x => x.FirstName).HasColumnName("FirstName").IsOptional();
          Property(x => x.MiddleName).HasColumnName("MiddleName").IsOptional();
          Property(x => x.LastName).HasColumnName("LastName").IsOptional();

          HasRequired(x => x.AuthProvider).WithMany(x => x.Users).Map(x => x.MapKey("AuthProviderId"));

          Map(mc => 
            mc.Properties(x => new 
              x.Id,
              x.Username,
              x.Email,
              x.AuthProvider
            );
            mc.ToTable("Users");
          );

          Map(mc => 
            mc.Properties(x => new  x.Id, x.FirstName, x.MiddleName, x.LastName );
            mc.ToTable("UserProfiles");
          );
        
      


     public class AuthProviderConfiuration : EntityTypeConfiguration<AuthProvider> 
        public AuthProviderConfiuration() 
          ToTable("AuthProviders");
          HasKey(x => x.Id).Property(x => x.Id).HasColumnName("AuthProviderId").IsRequired();
          Property(x => x.Name).HasColumnName("ProviderName").IsRequired();

        
      

【问题讨论】:

【参考方案1】:

导航属性不直接映射到表,因此您必须从映射到Users 表中删除AuthProvider

      Map(mc => 
        mc.Properties(x => new 
          x.Id,
          x.Username,
          x.Email
        );
        mc.ToTable("Users");
      );

我很确定我已经在某个地方回答了这个问题。

编辑:

这回答了你的问题。您想要实体拆分,这是实体拆分的正确映射。实体拆分不允许没有个人资料的用户。一旦你使用它,每个用户都必须有一个配置文件——这是实体拆分的先决条件。您的选择是:

您必须拥有每个用户的配置文件,然后才能使用实体拆分并将两个表映射到单个实体。如果您没有每个用户的个人资料,请修改您的数据库并确保每个用户都有空个人资料。 如果您没有每个用户的配置文件并且您不想创建空配置文件,则不能使用实体拆分 = 您不能将这些表映射到单个实体,您必须使用具有一对一关系的两个实体而是。

一旦您使用实体拆分,它的行为就与任何其他实体完全一样——它总是加载所有属性,这就是内部连接的原因。你不能只加载一半的属性(除了投影,但它仍然在内部执行主查询)。

【讨论】:

非常感谢,但这并不能回答我的问题。如果我删除它并调用 dbcontext.Users,它会与 UserProfiles 表进行内部连接。也就是说,如果我告诉它获取所有用户,EF 最终会与 UserProfiles 表进行内部联接,因此如果用户配置文件表中没有数据,我总是得到零行。

以上是关于使用 EF4.1 Fluent API 将具有导航属性的实体拆分为两个表的主要内容,如果未能解决你的问题,请参考以下文章

EF 4.1:使用 Fluent 映射从 Code First 中查找关键属性类型

实体框架(CTP5、Fluent API)。重命名导航属性的列

一对一或零对一实体框架代码优先 Fluent Api

Fluent API:如何将 HasComputedColumnSql 与外键对象一起使用

如何使用Fluent API在具有ASC / DESC排序的多个列上添加索引?

使用实体框架 Fluent Api 映射 System.Uri