我正在使用Entity Framework 4.3.1 Code-First,我需要在两个表之间拆分实体 . 这些表共享一个主键,它是1对1,但每个表上的列名称不相同 .
我不控制数据布局,也不能请求任何更改 .
例如,SQL表可以是
这将是我的实体......
public class MyEntity
{
public int Id {get; set;}
public string Name {get;set}
public string FromAnotherTable {get;set;}
}
这是我的映射 .
public class MyEntityMapping : EntityTypeConfiguration<MyEntity>
{
public MyEntityMapping()
{
this.Property(e => e.Id).HasColumnName("ThePrimaryKeyId");
this.Property(e => e.Name).HasColumnName("MyDatabaseName");
this.Property(e => e.FromAnothertable).HasColumnName("AnotherTableColumn");
this.Map(m =>
{
m.Properties(e =>
{
e.Id,
e.Name
});
m.ToTable("MainTable");
});
this.Map(m =>
{
m.Properties(e =>
{
e.Id,
e.FromAnotherTable
});
m.ToTable("ExtendedTable");
});
}
由于它们之间共享的密钥具有不同的列名,因此我不确定如何映射它 . 此映射将编译,但在运行时失败,因为EF发出SQL查找“ExtendedTable”表上的“ThePrimaryKeyId”列,该列不存在 .
EDIT 为了澄清,如果"ExtendedTable"上的PK遵循命名约定,我上面定义的内容可以(并且确实)起作用 . 但它没有改变架构 .
基本上,我需要EF发出的是一个类似的SQL语句
SELECT
[e1].*, /*yes, wildcards are bad. doing it here for brevity*/
[e2].*
FROM [MainTable] AS [e1]
INNER JOIN [ExtendedTable] AS [e2] /*Could be left join, don't care. */
ON [e1].[ThePrimaryKeyId] = [e2].[NotTheSameName]
但它似乎唯一想要发出的是
SELECT
[e1].*,
[e2].*
FROM [MainTable] AS [e1]
INNER JOIN [ExtendedTable] AS [e2]
ON [e1].[ThePrimaryKeyId] = [e2].[ThePrimaryKeyId] /* this column doesn't exist */
Edit 我在NSGaga 's suggestion. It didn'工作时再次尝试了一对一的方法,但结果如下 . 实体
public class MyEntity
{
public int Id { get; set; }
public int Name { get; set; }
public virtual ExtEntity ExtendedProperties { get; set; }
}
public class ExtEntity
{
public int Id { get; set; }
public string AnotherTableColumn { get; set; }
public virtual MyEntity MainEntry { get; set; }
}
这是映射类
public class MyEntityMapping : EntityTypeConfiguration<MyEntity>
{
public MyEntityMapping()
{
this.Property(e => e.Id).HasColumnName("ThePrimaryKeyId");
this.Property(e => e.Name).HasColumnName("MyDatabaseName");
this.ToTable("MainTable");
this.HasKey(e => e.Id);
this.HasRequired(e => e.ExtendedProperties).WithRequiredPrincipal(f => f.MainEntry);
}
}
public class ExtEntityMapping : EntityTypeConfiguration<ExtEntity>
{
public ExtEntityMapping()
{
this.Property(e => e.Id).HasColumnName("NotTheSameName");
this.Property(e => e.AnotherTableColumn).HasColumnName("AnotherTableColumn");
this.ToTable("ExtendedTable");
this.HasKey(e => e.Id);
this.HasRequired(e => e.MainEntry).WithRequiredDependent(f => f.ExtendedProperties);
}
}
此设置获取消息
"Column or attribute 'MyEntity_ThePrimaryKeyId' is not defined in 'ExtendedTable'"
将最终 Map 线更改为
this.HasRequired(e => e.MainEntry).WithRequiredDependent(f => f.ExtendedProperties).Map(m => M.MapKey("NotTheSameName"));
返回此消息
"Each property name in a type must be unique. property name 'NotTheSameName' was already defined."
更改映射键以使用父表中的列 MapKey("ThePrimaryKeyId")
. 返回此消息
"Column or attribute 'ThePrimaryKeyId' is not defined in 'ExtendedTable'"
从 ExtEntity
类中删除 Id
属性会引发错误,因为该实体没有定义的键 .
8 回答
我找不到任何明确说明两个表中列的名称必须相同的内容;但是我也找不到任何说它没有的东西,或者解释你将如何映射那个场景 . 我能找到的每个例子都有两个表中同名的密钥 . 在我看来,这是DbContext设计中的一个漏洞 .
我已经在这个问题上工作了几天,我最终做的是设置Id字段的列名称 within 映射片段的上下文 . 这样,您可以为Id(或依赖于Id的外键)提供与主表的Id不同的名称 .
如果你运行并调试它,你会发现它会给你一些你想要的东西:
将HasColumnName移动到映射中:
这里没有Visual Studio,但尝试使用1对1方法:
this.HasRequired(e => e.ExtendedProperties).HasConstraint((e,m)=> e.Id == m.Id);
Update:
以下是一些可能有用的链接(无法找到真正的参考链接)
How to declare one to one relationship using Entity Framework 4 Code First (POCO)
Entity Framework 4 CTP 4 Code First: how to work with unconventional primary and foreign key names
并且只是提供(如我所承诺的)1对1(两个实体,两个表)映射,以获得它的 Value .
这对我有用,在你的情况下应该......
...和测试代码类似......
这会创建以下SQL脚本,表格......
还有一张说明,根据我们上面的讨论......
这个''t the '分裂' - 但是
(a)代码首先IMO没有't allow anything like that (I tried that first and also modifying the migrations manually but it' s 'internally'全部基于预期的列名相同而且似乎没有办法绕过它,至少对于这个版本的EF .
(b)明智的表结构 - 可以使表格看起来完全符合您的需求(正如我之前所说的那样,我将它用于将现有的aspnet成员资格表(我无法更改)与我的用户表相关联,后者拥有自己的用户-id指向外部/ aspnet表和id .
没错,你不能使用一个C#模型类 - 但是C#方面更灵活,如果你可以控制应该产生相同效果的C#,至少在我看来(比如在测试中,你可以随时访问它)通过扩展实体,扩展实体和主列,他们're always matched 1 to 1 and stay '同步' .
希望这会有所帮助
注意:您不必担心fk id等 - 只需始终通过MainEntry访问并添加Main条目,id-s就可以了 .
EDIT:
您还可以执行以下操作,以获得只需处理一个类(即分类)的外观
......并像这样使用它......
...你也可以通过
WithRequiredPrincipal
而不是依赖来恢复fk的方向 .(如果你需要一对一的话,所有引用都必须是没有'virtual')
(并且可以将MainTable设为'internal',因为它不能从外部看到 - 它不能嵌套,因为EF不允许 - 被视为NotMapped)
......好吧,那是我能做到的最好的做:)
看起来它已在Entity Framework 6中修复 . 请参阅此问题http://entityframework.codeplex.com/workitem/388
我想建议使用这样的一些数据注释:
我遇到了这个问题,并通过添加Column属性以匹配两个列名来解决 .
[Key] [Column("Id")] public int GroupId { get; set; }