如何将基本实体字段映射到每个子类的不同列
How can I map a base entity field to different columns for each subclass
我有一个基本实体 class,我希望能够继承它,这样我只需为许多不同的特定于实体的存储库编写 1 GetById
方法。但是,由于遗留原因,我的某些数据库表中的 "Id" 列必须称为 "Code"。
我试过(简化版):
public class EntityBase{
int Id;
}
public class IdEntity : EntityBase{
}
public class CodeEntity : EntityBase{
}
然后在 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
}
这个构建很好,但是当我尝试 运行 它时,我得到一个 InvalidOperationException:
无法在实体类型 'CodeEntity' 上为 属性 'Id' 调用 属性,因为它被配置为导航 属性。 属性 只能用于配置标量属性。
我想做的事情是不可能的吗?这对我来说似乎不太可能,但是正确的方法是什么?
编辑:
事实证明,我实际尝试做的事情比我在此处发布的 "simplified" 代码复杂得多。我想这样做,这样我就可以拥有一个字符串或整数 ID,并使用相同的 GetById
方法。所以我创建了一个 class,它对字符串和 int 都进行了隐式转换,我认为这对 Entity Framework.
是可以的
不是。
运行time 错误是由于试图告诉 EF EntityID
类型的 属性 应该是我的密钥而引起的,而您不允许这样做。
我在 Microsoft 找不到关于 Entity Framework 中键值要求的任何文档,但我发现了另一个 SO 问题,它说键只允许标量和字节 []:Type safe keys with Entity Framework model
我无法得到上面的代码来编译或给出异常,因为你在尝试修复它后已经足够了。虽然我将描述如何编写您想要实现的场景。
如果你想在EF中使用EntityBase.Id
作为PK 属性,你需要将其设为public 属性。在您的代码中,它是一个私有字段(因为没有 get/set 方法)。所以你的 EntityBase
class 应该是这样的
public class EntityBase
{
public int Id { get; set; }
}
通过上述更改和 OnModelCreating
代码来映射有问题的实体类型,模型构建工作正常,创建具有所需 table 结构和名称的 tables。
以下是在 dbset 上实现通用 GetById
的小方法。它可以成为通用存储库甚至扩展方法的一部分。
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);
我有一个基本实体 class,我希望能够继承它,这样我只需为许多不同的特定于实体的存储库编写 1 GetById
方法。但是,由于遗留原因,我的某些数据库表中的 "Id" 列必须称为 "Code"。
我试过(简化版):
public class EntityBase{
int Id;
}
public class IdEntity : EntityBase{
}
public class CodeEntity : EntityBase{
}
然后在 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
}
这个构建很好,但是当我尝试 运行 它时,我得到一个 InvalidOperationException: 无法在实体类型 'CodeEntity' 上为 属性 'Id' 调用 属性,因为它被配置为导航 属性。 属性 只能用于配置标量属性。
我想做的事情是不可能的吗?这对我来说似乎不太可能,但是正确的方法是什么?
编辑:
事实证明,我实际尝试做的事情比我在此处发布的 "simplified" 代码复杂得多。我想这样做,这样我就可以拥有一个字符串或整数 ID,并使用相同的 GetById
方法。所以我创建了一个 class,它对字符串和 int 都进行了隐式转换,我认为这对 Entity Framework.
不是。
运行time 错误是由于试图告诉 EF EntityID
类型的 属性 应该是我的密钥而引起的,而您不允许这样做。
我在 Microsoft 找不到关于 Entity Framework 中键值要求的任何文档,但我发现了另一个 SO 问题,它说键只允许标量和字节 []:Type safe keys with Entity Framework model
我无法得到上面的代码来编译或给出异常,因为你在尝试修复它后已经足够了。虽然我将描述如何编写您想要实现的场景。
如果你想在EF中使用EntityBase.Id
作为PK 属性,你需要将其设为public 属性。在您的代码中,它是一个私有字段(因为没有 get/set 方法)。所以你的 EntityBase
class 应该是这样的
public class EntityBase
{
public int Id { get; set; }
}
通过上述更改和 OnModelCreating
代码来映射有问题的实体类型,模型构建工作正常,创建具有所需 table 结构和名称的 tables。
以下是在 dbset 上实现通用 GetById
的小方法。它可以成为通用存储库甚至扩展方法的一部分。
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);