Cly*_*yde 15 .net c# ado.net entity-framework-4 ef-code-first
我在设置Entity Framework 4模型时遇到问题.
Contact对象在数据库中公开为可更新视图.此外,由于数据库的历史记录,此联系人视图有两个不同的密钥,一个来自遗留系统.所以其他一些表引用了一个带有'ContactID'的联系人,而其他旧表引用了一个'LegacyContactID'.
由于这是一个视图,因此数据库中没有外键,我正在尝试在设计器中手动添加关联.但是,流畅的关联似乎没有提供指定引用哪个字段的方法.
我该如何建立这个模型?
public class vwContact
{
public int KeyField { get; set; }
public string LegacyKeyField { get; set; }
}
public class SomeObject
{
public virtual vwContact Contact { get; set; }
public int ContactId { get; set; } //references vwContact.KeyField
}
public class LegacyObject
{
public virtual vwContact Contact { get; set; }
public string ContactId { get; set; } //references vwContact.LegacyKeyField
}
ModelCreatingFunction(modelBuilder)
{
// can't set both of these, right?
modelBuilder.Entity<vwContact>().HasKey(x => x.KeyField);
modelBuilder.Entity<vwContact>().HasKey(x => x.LegacyKeyField);
modelBuilder.Entity<LegacyObject>().HasRequired(x => x.Contact).???
//is there some way to say which key field this reference is referencing?
}
Run Code Online (Sandbox Code Playgroud)
编辑 2:“新事物已经曝光,伙计” ——他的 Dudeness
经过更多的实验和新闻,我发现使用基类和具有不同键的子类本身无法工作。特别是在代码优先的情况下,如果基本实体没有显式映射到表,则必须定义一个键。
我留下了下面建议的代码,因为我仍然建议使用基类来实现 C# 的可管理性,但我在代码下面更新了我的答案并提供了其他解决方法选项。
不幸的是,事实揭示的是,由于 EF 4.1+ 代码优先的限制,如果不更改 SQL,您就无法实现您所寻求的目标。
public abstract class BaseContact
{
// Include all properties here except for the keys
// public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您愿意,可以通过 Fluent API 进行设置,但为了便于说明,我使用了数据注释
public class Contact : BaseContact
{
[Key]
public int KeyField { get; set; }
public string LegacyKeyField { get; set; }
}
public class LegacyContact : BaseContact
{
public int KeyField { get; set; }
[Key]
public string LegacyKeyField { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
引用或操作联系人对象的类应该像接口一样引用基类:
public class SomeCustomObject
{
public BaseContact Contact { get; set; }
}
Run Code Online (Sandbox Code Playgroud)如果稍后您需要以编程方式确定您正在使用的类型typeof()并相应地操作实体。
var co = new SomeCustomObject(); // assume its loaded with data
if(co.Contact == typeof(LegacyContact)
// manipulate accordingly.
Run Code Online (Sandbox Code Playgroud)正如我之前在评论中建议的那样,无论如何您都无法将它们映射到单个视图/表,因此您有几个选择:
A。将您的对象映射到其基础表,并更改从连接视图中提取的存储库和服务类上的“获取/读取”方法 - 或 -
b. 创建第二个视图并将每个对象映射到其适当的视图。
C。将一个实体映射到其基础表,并将一个实体映射到视图。
尝试(B),创建一个单独的视图,因为它需要对代码和数据库架构进行最少的更改(您不会摆弄基础表,也不会影响存储过程)。它还确保您的 EF C# POCO 具有同等功能(一个用于视图,一个用于表可能会导致异常)。米格尔下面的答案似乎与建议大致相同,所以如果可能的话我会从这里开始。
选项(C)似乎最糟糕,因为当映射到不同的 SQL 片段(表与视图)时,您的 POCO 实体的行为可能会出现不可预见的怪癖,从而导致编码问题。
选项(A),虽然它最符合 EF 的意图(实体映射到表),但这意味着要获得联接视图,您必须更改 C# 服务/存储库以与 EF 实体一起进行添加、更新、删除操作,但告诉类似拉/读的方法从联合视图中获取数据。这可能是您的最佳选择,但比(B)涉及更多工作,并且从长远来看也可能影响架构。复杂性越高,风险就越大。