【发布时间】:2015-07-29 10:58:41
【问题描述】:
设计背景:
我正在尝试为以下数据库结构创建代码优先的 EF6 映射:
数据库设计如下:我们没有将“CustomerID”作为所有相关实体(就业、费用、收入等)的外键,而是有一个包含 CustomerID 的 CustomerRelationship 表,然后一个“RelatedID”列,它将包含相关实体的键。例如,假设我为 CustomerID=1 添加了就业记录,那么将发生以下情况:
在 CustomerRelationship 中创建记录,设置 CustomerID = 1 RelatedID = {新的自动生成的就业 ID,假设为 5} CustomerRelationshipTypeID = 55(查找表中的 Id 表明 此记录属于雇佣类型)
在就业表中创建记录 (EmploymentID=5)
上述结构适用于与客户相关的所有实体。
我有为就业工作的关系映射,这是我的课程:
public abstract class EntityBase : IEntity
{
#region IEntity Members
public int Id { get; set; }
public DateTime CreatedDate { get; set; }
public int CreatedUserId { get; set; }
public int CreatedSource { get; set; }
public DateTime ModifiedDate { get; set; }
public int ModifiedUserId { get; set; }
public int? DataMigrationId { get; set; }
public bool IsActive { get; set; }
#endregion
}
public class Employment : EntityBase
{
// ... all properties here.. removed most so easier to read
public int EmploymentTypeId { get; set; }
**public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }**
}
public EmploymentMap()
{
this.HasKey(t => t.Id);
ToTable("tblEmployment");
Property(t => t.Id).HasColumnName("EmploymentID");
// Mapping for all properties follow
}
public abstract partial class CustomerRelationship : EntityBase
{
public int CustomerId { get; set; }
public decimal? PercentageShare { get; set; }
public int CustomerRelationshipTypeId { get; set; }
public int RelatedId { get; set; }
}
public class EmploymentRelationship : CustomerRelationship
{
public virtual Employment Employment { get; set; }
}
public EmploymentRelationshipMap()
{
this.HasKey(t => t.Id);
Map<EmploymentRelationship>(m =>
{
m.Requires("CustomerRelationshipTypeID").HasValue(55).IsRequired(); // Define lookup value for type of employment
m.ToTable("tblCustomerRelationship");
});
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
HasRequired(t => t.Employment)
.WithMany(t => t.EmploymentRelationships)
.HasForeignKey(t => t.RelatedId);
}
public class Customer : EntityBase
{
// Customer Properties...
public Customer()
{
EmploymentRelationships = new List<EmploymentRelationship>();
}
public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }
}
public CustomerMap()
{
this.HasKey(t => t.Id);
ToTable("tblCustomer");
Property(t => t.Id).HasColumnName("CustomerID");
}
public class CustomerContext
{
public CustomerContext()
: base(SymmetryCopy.context_connectionstring_main)
{
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Employment> Employments { get; set; }
#region Customer Relationship entity mappings
public virtual DbSet<EmploymentRelationship> EmploymentRelationships { get; set; }
#endregion
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new EmploymentMap());
#region Customer Relationship entity mappings
modelBuilder.Configurations.Add(new EmploymentRelationshipMap());
#endregion
}
}
CustomerRepo 查询上下文并返回结果:
public class CustomerRepository : BaseRepository<Customer, CustomerContext>, ICustomerRepository
{
public CustomerRepository() :
base(new CustomerContext())
{
}
public async Task<List<Employment>> GetEmployments(int customerId)
{
List<Employment> employments = new List<Employment>();
using (var context = new CustomerContext())
{
var employmentRelationships = context.EmploymentRelationships.Where(l => l.CustomerId == customerId).ToList();
employments = employmentRelationships.Select(x => x.Employment).ToList();
}
return employments;
}
}
上述方法 GetEmployments 然后返回与 CustomerID 匹配且 CustomerRelationshipTypeID = 55(Employments 的键值)的所有记录。请参阅下面的回报。
现在开始我的实际问题:
当我尝试连接另一个实体类型时,即:费用,遵循与就业相同的方法,创建 Expense.cs、ExpenseMap.cs、ExpenseRelationship.cs、ExpenseRelationshipMap.cs,在 ExpenseRElationshipMap.cs 中具有以下内容:
public class ExpenseRelationshipMap
{
public ExpenseRelationshipMap()
{
HasKey(t => t.Id);
Map<ExpenseRelationship>(m =>
{
m.Requires("CustomerRelationshipTypeID").HasValue(60).IsRequired();
m.ToTable("tblCustomerRelationship"); // Define lookup value for type of Expense
});
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
Property(t => t.PercentageShare).HasColumnName("PercentageShare");
HasRequired(t => t.Expense)
.WithMany(t => t.ExpenseRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
一旦我创建了 Map 条目,如上所示,当查询 GetEmployments() 方法时,我现在得到以下异常:
“实体类型 'ExpenseRelationship' 和 'EmploymentRelationship' 无法共享表“tblCustomerRelationship”,因为它们不在 相同的类型层次结构或没有有效的一对一外键 与它们之间的匹配主键的关系。",
我错过了什么?
更新
根据 jjj cmets,我更新了我的映射并创建了 CustomerRelationship.cs 基类。
public class Employment : EntityBase
{
public string EmployerName { get; set; }
public string EmployerContactFirstName { get; set; }
public string EmployerContactSurname { get; set; }
public virtual ICollection<EmploymentRelationship> EmploymentRelationships { get; set; }
}
public class Expense : EntityBase
{
public string Description { get; set; }
public virtual ICollection<ExpenseRelationship> ExpenseRelationships { get; set; }
}
public abstract class CustomerRelationship : EntityBase
{
public int CustomerId { get; set; }
public int? CustomerRelationshipTypeId { get; set; }
public int RelatedId { get; set; }
}
public class EmploymentRelationship : CustomerRelationship
{
public virtual Employment Employment { get; set; }
}
public class ExpenseRelationship: CustomerRelationship
{
public virtual Expense Expense{ get; set; }
}
public class CustomerRelationshipMap : BaseMap<CustomerRelationship>
{
public CustomerRelationshipMap()
{
ToTable("CustomerRelationship");
Map<EmploymentRelationship>(m => m.Requires("CustomerRelationshipTypeID").HasValue(55));
Map<ExpenseRelationship>(m => m.Requires("CustomerRelationshipTypeID").HasValue(60));
Property(t => t.Id).HasColumnName("CustomerRelationshipID");
Property(t => t.CustomerId).HasColumnName("CustomerID");
Property(t => t.RelatedId).HasColumnName("RelatedID");
}
public class EmploymentRelationshipMap : BaseMap<EmploymentRelationship>
{
public EmploymentRelationshipMap()
{
HasRequired(t => t.Employment)
.WithMany(t => t.EmploymentRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
public class ExpenseRelationshipMap : BaseMap<ExpenseRelationship>
{
public ExpenseRelationshipMap()
{
HasRequired(t => t.Expense)
.WithMany(t => t.ExpenseRelationships)
.HasForeignKey(t => t.RelatedId);
}
}
public class CustomerContext : BaseContext
{
public CustomerContext()
: base(context_connectionstring_main)
{
}
public virtual DbSet<Customer> Customers { get; set; }
public virtual DbSet<Employment> Employments { get; set; }
public virtual DbSet<CustomerRelationship> CustomerRelationships { get; set; }
public virtual DbSet<EmploymentRelationship> EmploymentRelationships { get; set; }
public virtual DbSet<ExpenseRelationship> ExpenseRelationships { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new EmploymentMap());
modelBuilder.Configurations.Add(new CustomerRelationshipMap());
modelBuilder.Configurations.Add(new EmploymentRelationshipMap());
modelBuilder.Configurations.Add(new ExpenseRelationshipMap());
}
}
当我这样查询客户上下文时:
var relationships = context.CustomerRelationships.Where(l => l.CustomerId == customerId).ToList();
我得到以下异常:
"外键组件 'RelatedId' 不是在 输入“就业关系”。验证它没有被明确地 从模型中排除并且它是一个有效的原始属性。",
【问题讨论】:
-
好的,外键组件的错误是有道理的。我猜您不能将基类属性用于派生类外键关联。见stackoverflow.com/questions/11900155/… 和stackoverflow.com/questions/25619452/…
-
您正在使用关系数据库。为什么不想使用关系来建模关系?
标签: c# entity-framework ef-code-first entity-framework-6