EF6: Code First Complex Type
c#, domain-driven-design, entity-framework, sql-server-ce
Solution
Try this:
public class AuditInformation
{
public long CreatedByUserId { get; set; }
public DateTime CreatedDate { get; set; }
}
public abstract class AuditInfo
{
public AuditInformation AuditDetails { get; set; }
public AuditInfo()
{
this.AuditDetails = new AuditInformation();
this.AuditDetails.CreatedByUserId = 0;
this.AuditDetails.CreatedDate = DateTime.Now;
}
}
public User : AuditInfo
{
private User(){}
public long Id {get; private set;} // dont ask, inherited legacy database
public string UserId { get; private set; }
public string Domain { get; private set; }
//..domain logic etc
}
public partial class myContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Conventions.Remove<PluralizingTableNameConvention>();
mb.ComplexType<Domain.Model.AuditInformation>();
mb.ComplexType<Domain.Model.AuditInformation>().Property(a => a.CreatedDate).HasColumnName("Created_On");
mb.ComplexType<Domain.Model.AuditInformation>().Property(a => a.CreatedByUserId).HasColumnName("Created_By");
mb.Entity<Cricketer>().Map(a =>
{
a.Property(x => x.Id).HasColumnName("Id");
a.Property(x => x.UserId).HasColumnName("User_Id");
a.Property(x => x.Domain).HasColumnName("User_Dmain");
a.Property(x => x.AuditDetails.CreatedByUserId).HasColumnName("CreatedByUserId");
a.Property(x => x.AuditDetails.CreatedDate).HasColumnName("CreatedDate");
})
.HasKey(x => x.ID)
.ToTable("Tbl_User"); //<==Again, dont ask
}
}
Problem
I'm having trouble getting entity framework to flatten my domain entity classes with Value Objects (complex type) fields to one table. Everything works if I tell my model builder to ignore my value objects/complex type, but that results in all the attributes of the value object being missed in my tables. As soon as I remove the ignore statement i get "A value shared across entities is created in more than one location". If I look in the resulting CE SQL file I see an additional table named after my Domain class appended with a 1 and containing only the Value Object parameters. Some Code: My domain Classes: ``` public User { private User(){} public long Id {get; private set;} // dont ask, inherited legacy database public string UserId { get; private set; } public string Domain { get; private set; } public AuditIformation AuditDetails {get ; private set;} //..domain logic etc } public AuditInformation : IValueObject { public long CreatedByUserId { get; private set; } public DateTime CreatedDate { get; private set; } } ``` My repository project (going code first) has got this: ``` public partial class myContext : DbContext { protected override void OnModelCreating(DbModelBuilder mb) { mb.Conventions.Remove<PluralizingTableNameConvention>(); mb.ComplexType<Domain.Model.AuditInformation>(); mb.ComplexType<Domain.Model.AuditInformation>().Property(a => a.CreatedDate).HasColumnName("Created_On"); mb.ComplexType<Domain.Model.AuditInformation>().Property(a => a.CreatedByUserId).HasColumnName("Created_By"); //This line lets everything work but doesn't include my //AuditInformation attributes in my User Table. mb.Ignore<Domain.Model.AuditInformation>(); // <== I think I need to remove this //.. mb.Entity<User>().Map(a => { a.Property(x => x.Id).HasColumnName("Id"); a.Property(x => x.UserId).HasColumnName("User_Id"); a.Property(x => x.Domain).HasColumnName("User_Dmain"); }) .HasKey(x => x.Id) .ToTable("Tbl_User"); //<==Again, dont ask } } ``` What I want to get is a table looking like: ``` [TBL_USER] ID AS BIGINT, USER_ID as VARCHAR(MAX), USER_DMAIN AS VARCHAR(MAX), CREATED_ON as DATE, CREATED_BY as BIGINT ``` But what im getting is only: ``` [TBL_USER] ID AS BIGINT, USER_ID as VARCHAR(MAX), USER_DMAIN AS VARCHAR(MAX), ``` and if I remove the ignore line i get this bonus freak table ``` [USER1] <<==Note, named after the domain class, not the destination table.. ID AS BIGINT, CREATED_ON as DATE, CREATED_BY as BIGINT ``` and a whole bunch of error when I try to use my repository: ``` ----> System.Data.Entity.Infrastructure.DbUpdateException : A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns. ----> System.Data.Entity.Core.UpdateException : A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns. ----> System.ArgumentException : An item with the same key has already been added. TearDown : System.NullReferenceException : Object reference not set to an instance of an object. ``` Ive done a lot of searching but I just cant find any concrete examples of persisting my value object attributes into the tables created for my domain objects. Can someone show me where I'm going wrong?