Reputation: 399
I have a base entity class, which I want to be able to inherit from so that I only have to write 1 GetById
method for lots of different entity-specific repositories. However, the "Id" column in some of my database tables has to be called "Code" for legacy reasons.
I tried to do (simplified version):
public class EntityBase{
int Id;
}
public class IdEntity : EntityBase{
}
public class CodeEntity : EntityBase{
}
And then in the DbContext:
modelBuilder.Entity<IdEntity>(entity =>
{
entity.HasKey(e=>e.Id).HasName("PK_IdEntity");
entity.Property(e=>e.Id).HasColumnName("ID");
}
modelBuilder.Entity<CodeEntity>(entity =>
{
entity.HasKey(e=>e.Id).HasName("PK_CodeEntity");
entity.Property(e=>e.Id).HasColumnName("Code"); //this seems to be where it breaks
}
This builds fine, but when I try to run it, I get an InvalidOperationException: Cannot call Property for the property 'Id' on entity type 'CodeEntity' because it is configured as a navigation property. Property can only be used to configure scalar properties.
Is what I'm trying to do impossible? That seems unlikely to me, but then what would be the correct way to do it?
What I was actually trying to do turns out to be much more complex than the "simplified" code I posted here. I wanted to make it so I could have a string or int ID, and use the same GetById
method. So I created a class that had implicit conversions to both string and int, which I thought would be ok for Entity Framework.
It's not.
The runtime error was caused by trying to tell EF that a property with the EntityID
type should be my key, which you're not allowed to do.
I couldn't find any documentation from Microsoft about requirements for key values in Entity Framework, but I found another SO question that said only scalars and byte[] are allowed for keys: Type safe keys with Entity Framework model
Upvotes: 1
Views: 1401
Reputation: 2459
I could not get above code to compile or give the exception as you were getting enough after trying to fix it. Though I will describe how to write the scenario you trying to achieve.
If you want to use EntityBase.Id
as PK property in EF, you need to make it public property. In your code, it is a private field (since no get/set methods). So your EntityBase
class should look like this
public class EntityBase
{
public int Id { get; set; }
}
With above changes and OnModelCreating
code to map entity types as posted in question, the model building works correctly creating tables with desired table structure and names.
Following is a small method implementing a generic GetById
on dbset. It can be made part of generic repository or even extension method.
public static T GetById<T>(DbSet<T> dbset, int id)
where T : EntityBase
{
return dbset.FirstOrDefault(e => e.Id == id);
}
// example
var entity = GetById(db.Set<IdEntity>(), 2);
Upvotes: 1