Reputation: 1503
Here's my entity class:
public abstract class Entity: IEntity
{
public Guid? Id { get; set; }
public bool IsDead { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public ICollection<EntityAccess> AccessList { get; set; }
public ICollection<Message> Discussion { get; set; }
public User Owner { get; set; }
}
Most of my entities (including User) inherit from this class. OnModelCreating, they all go through this code:
m.MapInheritedProperties();
m.ToTable(entity.Name); };
After EF creates the database, something really peculiar happens. The properties inherited from Entity are indeed mapped to every table, except the Owner property. Owner is not mapped, unlike the other inherited properties. What could explain this?
Additional info: my entities are simple POCO objects, no annotations, no constructors, no nothing. For example, here's the User entity:
public class User : RuntimeEntity
{
public string Email { get; set; }
public ICollection<UserGroup> Groups { get; set; }
public byte[] Password { get; set; }
public ICollection<Membership> Memberships { get; set; }
}
Edit:
Since this problem is still going on, here's the full model:
namespace ConSol.Templex.Data.Entities
{
public abstract class Association : IEntity
{
public Guid? Id { get; set; }
[NotMapped]
public virtual RuntimeEntity Entity1 { get; set; }
[NotMapped]
public virtual RuntimeEntity Entity2 { get; set; }
}
public class Attachment : RuntimeEntity
{
public AttachmentValidity Validity { get; set; }
public ICollection<Blob> Versions { get; set; }
public Profile Profile { get; set; }
#region Computed properties
public string Name
{
get
{
return this.Versions.Last().Name;
}
}
#endregion
}
public enum AttachmentValidity
{
Unverified,
Verified,
WorkInProgress
}
public class Blob : RuntimeEntity
{
public string Name { get; set; }
public byte[] Data { get; set; }
public Attachment Attachment { get; set; }
public WorkLog WorkLog { get; set; }
}
public class EntityAccess : Association
{
#region Association implementation
public override RuntimeEntity Entity1 { get { return this.Entity; } }
public override RuntimeEntity Entity2
{
get
{
return this.UserGroup ?? this.User as RuntimeEntity;
}
set
{
if (value is User) this.User = (User)value; else this.UserGroup = (UserGroup)value;
}
}
#endregion
public RuntimeEntity Entity { get; set; }
public UserGroup UserGroup { get; set; }
public User User { get; set; }
}
}
?
public interface IEntity
{
}
}
?
public abstract class MasterEntity : IEntity
{
public string Code { get; set; }
public string Name { get; set; }
}
public class Membership : Association
{
#region Association implementation
public override RuntimeEntity Entity1 { get { return this.User; } }
public override RuntimeEntity Entity2 { get { return this.UserGroup; } }
#endregion
public User User { get; set; }
public UserGroup UserGroup { get; set; }
public bool IsAdmin { get; set; }
}
public class Message : RuntimeEntity
{
public string Text { get; set; }
public RuntimeEntity RuntimeEntity { get; set; }
#region Computed properties
public User Author
{
get
{
return this.Owner;
}
}
#endregion
}
public class Parameter : RuntimeEntity
{
public string Code { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public Worker Worker
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
}
public class ParameterValue : ConSol.Templex.Data.Entities.RuntimeEntity
{
public string Value { get; set; }
public Parameter Parameter { get; set; }
public Worker Worker { get; set; }
public Profile Profile
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}
}
public class ProductStatus : RuntimeEntity
{
public Profile Profile { get; set; }
public Guid ProductId { get; set; }
public ExportStatus Status { get; set; }
public WorkLog WorkLog { get; set; }
public enum ExportStatus
{
Exported,
Imported,
Error
}
}
public class Profile : RuntimeEntity
{
public string Name { get; set; }
public ICollection<Attachment> Attachments { get; set; }
public ICollection<ParameterValue> Parameters { get; set; }
public ICollection<WorkLog> WorkLogs { get; set; }
public Worker Exporter { get; set; }
public Worker Importer { get; set; }
public TimeSpan? Frequency { get; set; }
public DateTime FirstRun { get; set; }
public string Destination { get; set; }
public ICollection<ProductStatus> ProductQueue { get; set; }
}
}
?
public abstract class RuntimeEntity : IEntity, ISoftDeletable
{
public Guid? Id { get; set; }
public bool IsDead { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
//public ICollection<EntityAccess> AccessList { get; set; }
public ICollection<Message> Discussion { get; set; }
public User Owner { get; set; }
/// <summary>
/// This defines the default filter for all entities
/// </summary>
public static Expression<Func<TIn,bool>> DefaultFilterFor<TIn>(User user)
where TIn : RuntimeEntity
{
return x => true;
}
/// <summary>
/// This defines an optional filter to be used most of the time
/// </summary>
public static Expression<Func<TIn, bool>> AdditionalFilterFor<TIn>(User user)
where TIn : RuntimeEntity
{
return x => !x.IsDead;
}
}
public class Schedule : RuntimeEntity
{
public DateTime Start { get; set; }
public TimeSpan Frequency { get; set; }
}
public class User : RuntimeEntity
{
public string Email { get; set; }
public ICollection<UserGroup> Groups { get; set; }
public byte[] Password { get; set; }
public ICollection<Membership> Memberships { get; set; }
}
public class UserGroup : RuntimeEntity
{
public string CustomerId { get; set; }
public string Name { get; set; }
public bool IsSuperGroup { get; set; }
public ICollection<Membership> Memberships { get; set; }
#region Computed properties
public IEnumerable<User> Admins
{
get
{
return this.Memberships.Where(x => x.IsAdmin).Select(x => x.User);
}
}
#endregion
}
public class Worker : RuntimeEntity
{
public ICollection<Parameter> Parameters { get; set; }
public string AssemblyName { get; set; }
public byte[] Assembly { get; set; }
public WorkType Work { get; set; }
public enum WorkType
{
Import,
Export
}
}
public class WorkerMessage : RuntimeEntity
{
public string Message { get; set; }
public MessageType Outcome { get; set; }
public WorkLog WorkLog { get; set; }
public enum MessageType
{
Information,
Warning,
Error
}
}
public class WorkLog : RuntimeEntity
{
public DateTime End { get; set; }
public Profile Profile { get; set; }
public Worker Worker { get; set; }
public WorkResult Result { get; set; }
public ICollection<Blob> Files { get; set; }
public ICollection<WorkerMessage> Report { get; set; }
}
public enum WorkResult
{
Success,
Warning,
Failure
}
}
}
And here's the dbcontext:
public class TemplexDB : DbContextBase
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Attachment>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Attachment");
});
modelBuilder.Entity<Blob>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Blob");
});
modelBuilder.Entity<Message>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Message");
});
modelBuilder.Entity<Parameter>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Parameter");
});
modelBuilder.Entity<ParameterValue>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("ParameterValue");
});
modelBuilder.Entity<ProductStatus>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("ProductStatus");
});
modelBuilder.Entity<Profile>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Profile");
});
modelBuilder.Entity<Schedule>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Schedule");
});
modelBuilder.Entity<User>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("User");
});
modelBuilder.Entity<UserGroup>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("UserGroup");
});
modelBuilder.Entity<Worker>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Worker");
});
modelBuilder.Entity<WorkerMessage>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("WorkerMessage");
});
modelBuilder.Entity<WorkLog>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("WorkLog");
});
modelBuilder.Entity<EntityAccess>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("EntityAccess");
});
modelBuilder.Entity<Membership>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Membership");
});
}
public DbSet<Attachment> Attachments { get; set; }
public DbSet<Blob> Blobs { get; set; }
public DbSet<Message> Messages { get; set; }
public DbSet<Parameter> Parameters { get; set; }
public DbSet<ParameterValue> ParameterValues { get; set; }
public DbSet<ProductStatus> ProductStatuses { get; set; }
public DbSet<Profile> Profiles { get; set; }
public DbSet<Schedule> Schedules { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<UserGroup> UserGroups { get; set; }
public DbSet<Worker> Workers { get; set; }
public DbSet<WorkerMessage> WorkerMessages { get; set; }
public DbSet<WorkLog> WorkLogs { get; set; }
// associations
public DbSet<EntityAccess> EntityAccess { get; set; }
public DbSet<Membership> Membership { get; set; }
}
Upvotes: 0
Views: 2388
Reputation: 10416
Your problem isn't in the code above, using your sample code I built the following model:
public abstract class Entity
{
public Guid? Id { get; set; }
public bool IsDead { get; set; }
public DateTime Created { get; set; }
public DateTime Modified { get; set; }
public ICollection<EntityAccess> AccessList { get; set; }
public ICollection<Message> Discussion { get; set; }
public User Owner { get; set; }
}
public class EntityAccess
{
public int Id { get; set; }
}
public class Message
{
public int Id { get; set; }
}
public class Structure : Entity
{
public string Property { get; set; }
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public ICollection<UserGroup> Groups { get; set; }
public byte[] Password { get; set; }
public ICollection<Membership> Memberships { get; set; }
}
public class UserGroup
{
public int Id { get; set; }
}
public class Membership
{
public int Id { get; set; }
}
public class Model : DbContext
{
public DbSet<Structure> Structures { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<EntityAccess> EntityAccesses { get; set; }
public DbSet<Message> Messages { get; set; }
public DbSet<UserGroup> UserGroups { get; set; }
public DbSet<Membership> Memberships { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Structure>()
.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Structure");
});
}
}
Which generated this database:
As you can see, there's an Owner_Id property on structure which is mapping the Owner to the structure table.
Upvotes: 3