我有一个如下所示的数据库。是的,我知道,我继承了一个糟糕的设计,但现在不能改变。基本上,每个客户都可以获得主要和次要的联系信息:
客户
ContactInfo
我希望我的实体框架6域模型看起来如下:
public class Customer
{
public int Id { get; set; }
public string CustomerNumber { get; set; }
public ContactInfo PrimaryContactInfo { get; set; }
public ContactInfo SecondaryContactInfo { get; set; }
}
public class ContactInfo
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public DateTime? UpdatedAt { get; set; }
public virtual Customer Customer { get; set; }
}是否有一种方法来设置映射,以便这是可能的?本质上,将列"primary__“映射到ContactInfo的一个实例,将列"secondary__”映射到另一个实例,并将一些列映射到两个实例?
或者,可以将字段映射到两个复杂类型的实例:
public class ContactInfo
{
public int CustomerId { get; set; }
public SingleContactInfo Primary { get; set; }
public SingleContactInfo Secondary { get; set; }
public virtual Customer Customer { get; set; }
}
public class SingleContactInfo
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}发布于 2016-01-02 00:20:09
第一个解决方案(继承)无法完成,因为不可能将继承方案中的两个实体保存到一个数据库记录中。
第二种解决方案(复杂类型)确实有效,但您必须牺牲将ContactInfo作为独立实体来处理并在模型中包含updated_at的能力。(因为updated_at不能两次映射到一个复杂类型的属性)。
我看到的唯一方法是将实体映射到数据模型,同时保持ContactInfo作为一个独立的实体集(几乎)和读写updated_at的能力,即通过表拆分。
在这个映射中,表ContactInfo被分成两个实体-- ContactInfoPrimary和ContactInfoSecondary。Customer与ContactInfoPrimary有1:1的关联,其中包含ContactInfoSecondary。
看上去是这样的:
课程:
public partial class Customer
{
public int Id { get; set; }
public string CustomerNumber { get; set; }
public virtual ContactInfoPrimary ContactInfoPrimary { get; set; }
}
public abstract class ContactInfo
{
public int CustomerId { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
public class ContactInfoPrimary : ContactInfo
{
public DateTime UpdatedAt { get; set; }
public virtual Customer Customer { get; set; }
public virtual ContactInfoSecondary ContactInfoSecondary { get; set; }
}
public class ContactInfoSecondary : ContactInfo
{ }映射:
class CustomerMap : EntityTypeConfiguration<Customer>
{
public CustomerMap()
{
ToTable("Customer");
HasKey(c => c.Id);
Property(c => c.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.HasColumnName("id");
Property(c => c.CustomerNumber)
.HasColumnName("customer_number");
HasOptional(c => c.ContactInfoPrimary).WithRequired(ci => ci.Customer);
}
}
class ContactInfoPrimaryMap : EntityTypeConfiguration<ContactInfoPrimary>
{
public ContactInfoPrimaryMap()
{
ToTable("ContactInfo");
HasKey(ci => ci.CustomerId);
Property(ci => ci.CustomerId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)
.HasColumnName("customer_id");
Property(ci => ci.UpdatedAt).HasColumnName("updated_at");
Property(ci => ci.Name).HasColumnName("primary_name");
Property(ci => ci.Email).HasColumnName("primary_email");
Property(ci => ci.Phone).HasColumnName("primary_phone");
// This, and the ToTable statements, define the table splitting.
HasRequired(ci => ci.ContactInfoSecondary).WithRequiredPrincipal();
}
}
class ContactInfoSecondaryMap : EntityTypeConfiguration<ContactInfoSecondary>
{
public ContactInfoSecondaryMap()
{
ToTable("ContactInfo");
HasKey(ci => ci.CustomerId);
Property(ci => ci.CustomerId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None)
.HasColumnName("customer_id");
Property(ci => ci.Name).HasColumnName("secondary_name");
Property(ci => ci.Email).HasColumnName("secondary_email");
Property(ci => ci.Phone).HasColumnName("secondary_phone");
}
}以及背景:
public partial class TestSO : DbContext
{
public TestSO() : base("name=TestSO")
{ }
public virtual DbSet<ContactInfoPrimary> ContactInfoes { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new CustomerMap());
modelBuilder.Configurations.Add(new ContactInfoPrimaryMap());
modelBuilder.Configurations.Add(new ContactInfoSecondaryMap());
}
}现在您可以创建一个包含联系人信息的Customer,如下所示:
var cis = new ContactInfoSecondary
{
Name = "Name2",
Email = "email2",
Phone = "phone2"
};
var cip = new ContactInfoPrimary
{
Name = "Name1",
Email = "email1",
Phone = "phone1",
UpdatedAt = DateTime.Today,
ContactInfoSecondary = cis
};
var cst = new Customer
{
ContactInfoPrimary = cip,
CustomerNumber = "number-nine"
};
context.Customers.Add(cst);
context.SaveChanges();以下是如何获取所有信息的客户:
context.Customers.Include(c => c.ContactInfoPrimary.ContactInfoSecondary)或单独提供联系信息:
context.ContactInfoes.Include(c => c.ContactInfoSecondary)你明白我为什么说你几乎可以独立获得ContactInfo了。不完全是。你只能在初选中获得第二名。
发布于 2016-01-01 04:18:07
如果可以从CustomerID类中删除ContactInfo和Customer引用,则可以尝试以下操作:
将ContactInfo注册为ComplexType:
modelBuilder.ComplexType<ContactInfo>();根据Customer对象上的每个实例定义列的特定名称(我只是演示如何为name属性这样做):
modelBuilder.Entity<Customer>().Property(p => p.PrimaryContactInfo.Name).HasColumnName("primary_name");
modelBuilder.Entity<Customer>().Property(p => p.SecondaryContactInfo.Name).HasColumnName("secondary_name");https://stackoverflow.com/questions/34550229
复制相似问题