Entity Framework - Discriminator problem with TPH
I am getting Invalid column name 'Discriminator'
whilst saving a record. (Code First, EF4.1)
I have an entity I wish to track via EF:
public class Audit
public virtual string p1
public virtual string p2
i have a specialism UserAudit, that adds no new virtual properties, it just sets up base ready for audit
public class UserAudit : Audit
public UserAudit() { p1 = someval; }
And the config:
public class AuditConfiguration : EntityTypeConfiguration<Audit>
{
public AuditConfiguration()
{
ToTable("_AUDIT");
HasKey(c => c.Id);
Property(c => c.Id).HasColumnName("AUDIT_ID");
}
}
And the repo:
public class AuditRepository : IAuditRepository
{
public void LogAudit(Audit audit)
{
using (var db = new AuditContext())
{
db.Audits.Add(audit);
db.SaveChanges();
}
}
}
开发者_高级运维
What do i need to do to tell EF to ignore/handle the specialism correctly when i repo.LogAudit( userAudit );
?
From the exception message Invalid column name 'Discriminator'
I would conclude that you didn't let EF 4.1 create the database table _AUDIT
because otherwise EF would have created a column called Discriminator
to the table. Perhaps you have an existing database table without such a column. When EF tries to save the entity it wants to store a value representing the concrete type you are saving into the discriminator column - but the column doesn't exist. Hence the exception.
Edit
So, you need a discriminator column. You can define your own custom discriminator column like so:
public class AuditConfiguration : EntityTypeConfiguration<Audit>
{
public AuditConfiguration()
{
ToTable("_AUDIT");
HasKey(c => c.Id);
Property(c => c.Id).HasColumnName("AUDIT_ID");
Map<Audit>(m => m.Requires("Type").HasValue<byte>(0).IsRequired());
Map<UserAudit>(m => m.Requires("Type").HasValue<byte>(1).IsRequired());
}
}
This would use a non-nullable tinyint
column Type
in the _AUDIT
table which has value 0
for base Audit
type objects and value 1
for the derived UserAudit
type objects.
@Slauma is absolutely correct and you should use his solution. I'm just adding explanation why this happens.
Inheritance in entities must be modelled in database because when you load the entity from the database, EF must know if it should materialize Audit
or UserAudit
instance. By default EF uses something called Table per Hierarchy inheritance where base type and all subtypes are stored in the same table. To support such scenario EF expects additional column in the table called by default Discriminator. This column will be used to differ stored instance - by default it includes names of types.
In my case, the non EF model was inheriting from an EF Model. Instead of inheritance, I have copied all the properties to the non EF Model and that was the solution for me.
public class ApplicationContext : DbContext
{
public DbSet<Person> Persons { get; set; }
}
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
}
Before:
public class PersonWithExtraInfo:Person
{
public string ExtraInfo { get; set; }
}
After:
public class PersonWithExtraInfo
{
public int PersonId { get; set; }
public string Name { get; set; }
public string ExtraInfo { get; set; }
}
精彩评论