【发布时间】:2016-11-14 15:45:23
【问题描述】:
我需要使用 EF6 和 CodeFirst 方法在新应用程序下转换一些现有数据库。我正在与继承中的映射约定作斗争。有一个最小(不)工作的例子:
假设我有两个表:一个 Parent 和一个 Child。
CREATE TABLE A_PARENT (
A_PAR_ParentId UNIQUEIDENTIFIER PRIMARY KEY,
A_PAR_data VARCHAR(255)
)
CREATE TABLE B_CHILD (
B_CHL_ChildId UNIQUEIDENTIFIER PRIMARY KEY FOREIGN KEY REFERENCES A_PARENT(A_PAR_ParentId),
B_CHL_childData VARCHAR(255)
)
我成功地解决了您可以看到的表格前缀,例如使用自定义属性的“A_PAR”。我相信 EF 完全知道哪个属性属于哪个列,哪个是主键。除了继承,一切都很好。因为当我尝试获取所有 Children 时,最终会出现 SQL 错误,因为 EF 会生成如下查询:
SELECT
'0X0X' AS [C1],
[Extent1].[A_PAR_ParentId] AS [A_PAR_ParentId],
[Extent1].[A_PAR_Data] AS [A_PAR_Data],
[Extent2].[B_CHL_ChildId] AS [B_CHL_ChildId],
[Extent2].[B_CHL_ChildData] AS [B_CHL_ChildData]
FROM [dbo].[A_PARENT] AS [Extent1]
INNER JOIN [dbo].[B_CHILD] AS [Extent2] ON [Extent1].[A_PAR_ParentId] = [Extent2].[A_PAR_ParentId]
查询中唯一不正确的是连接谓词 - 表 B_CHILD 中没有 A_PAR_ParentId 这样的列。
在构建继承链时,如何强制EntityFramework使用实体的主键作为外键?我正在寻找一些基于约定的通用解决方案,因为数据库中的所有表都使用这种模式(如果类型/表是继承的 => 主键是父主键的外键并且没有复合键全部)。也许我正在寻找某种方式来告诉 EF PK 也是一个 FK 但没有导航属性。
--编辑:更多代码
模型非常简单:
[ModulePrefix("A"), TablePrefix("PAR")]
public class Parent
{
public Guid ParentId { get; set; }
public string Data { get; set; }
}
[ModulePrefix("B"), TablePrefix("CHL")]
public class Child : Parent
{
public Guid ChildId { get; set; }
public string ChildData { get; set; }
}
以及配置:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Types()
.Where(type => !type.GetCustomAttributes(false).OfType<TableAttribute>().Any() && type.GetCustomAttributes(false).OfType<ModulePrefixAttribute>().Any())
.Configure(config => config.ToTable(
ComposeDbName(GetModulePrefix(config.ClrType),
CamelCaseToUnderscore(GetClassName(config.ClrType)).ToUpper())
));
modelBuilder.Properties()
.Where(property => property.DeclaringType.GetCustomAttributes(false).OfType<TablePrefixAttribute>().Any() && property.DeclaringType == property.ReflectedType)
.Configure(config => config.HasColumnName(ComposeDbName(
GetModulePrefix(config.ClrPropertyInfo.DeclaringType),
GetTablePrefix(config.ClrPropertyInfo.DeclaringType),
config.ClrPropertyInfo.Name
)));
modelBuilder.Properties()
.Where(property => property.Name == property.DeclaringType.Name + "Id" && property.ReflectedType == property.DeclaringType)
.Configure(config => config.IsKey());
modelBuilder.Properties()
.Where(property => property.PropertyType.IsClass || Nullable.GetUnderlyingType(property.PropertyType) != null)
.Configure(config => config.IsOptional());
}
还有一些更私有的方法使用列/表名称。我认为此时这并不重要,因为列/表名称似乎已得到很好的解析。
【问题讨论】:
-
让我们看看与上述数据库表相关的 Code First 模型/配置。
-
我刚刚在问题中添加了一些代码。
-
Child.ChildId字段导致问题。 -
Ivan:看来你是对的。我刚刚看到一些例子说像你这样的话。所以我必须只将标识符属性放置到基类中吗?后代表的主键和它的名字呢?我不想把它命名为
B_CHILD.B_CHL_ParentId,而是B_CHILD.B_CHL_ChildId。
标签: c# entity-framework inheritance ef-code-first code-first