c# - View 中具有多个(单独的)键的 Entity Framework 关联

标签 c# .net entity-framework-4 ado.net ef-code-first

我在设置 Entity Framework 4 模型时遇到问题。

联系人对象作为可更新 View 在数据库中公开。同样由于数据库的历史,这个 Contact View 有两个不同的键,一个来自遗留系统。因此,其他一些表使用“ContactID”引用联系人,而其他较旧的表使用“LegacyContactID”引用联系人。

由于这是一个 View ,数据库中没有外键,我正在尝试在设计器中手动添加关联。但是流畅的关联似乎没有提供指定引用哪个字段的方法。

我如何构建这个模型?

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?
}

最佳答案

编辑 2:“新事物已经曝光,伙计” - His Dudeness

经过更多的实验和新闻,我发现使用具有不同键的基类和子类本身是行不通的。特别是对于代码优先,如果基本实体未显式映射到表,则它们必须定义一个键。

我在下面留下了建议的代码,因为我仍然建议使用基类来实现 C# 可管理性,但我在代码下面更新了我的答案并提供了其他解决方法选项。

不幸的是,事实表明,由于 EF 4.1+ 代码优先的限制,如果不更改 SQL,您将无法完成您寻求的目标。


基础联系人类

public abstract class BaseContact
{
   // Include all properties here except for the keys
   // public string Name { get; set; }
}

实体类

如果您愿意,可以通过流畅的 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; }    
}

使用实体

  1. 引用或操作联系人对象的类应该像接口(interface)一样引用基类:

    public class SomeCustomObject
    {
       public BaseContact Contact { get; set; }
    }
    
  2. 如果稍后您需要以编程方式确定您正在使用的类型,请使用 typeof() 并相应地操作实体。

    var co = new SomeCustomObject(); // assume its loaded with data
    if(co.Contact == typeof(LegacyContact)
        // manipulate accordingly.
    

新选项和解决方法

  1. 正如我之前在评论中建议的那样,您无论如何都无法将它们映射到单个 View /表,因此您有几个选择:

    一个。将您的对象映射到它们的基础表并更改您在存储库和服务类上的“获取/读取”方法从联合 View 中提取 - 或 -

    创建第二个 View 并将每个对象映射到相应的 View 。

    将一个实体映射到其基础表,将一个实体映射到 View 。

总结

首先尝试(B),创建一个单独的 View ,因为它需要对代码和数据库架构进行最少的更改(您不会摆弄底层表,也不会影响存储过程)。它还确保您的 EF C# POCO 将等效运行(一个 View 和一个表可能会导致怪癖)。 Miguel 在下面的回答似乎与建议大致相同,所以如果可能的话,我会从这里开始。

选项 (C) 似乎最糟糕,因为当映射到不同的 SQL 片段(表与 View )时,您的 POCO 实体可能会表现出无法预料的怪癖,从而导致编码问题。

选项 (A),虽然它最符合 EF 的意图(实体映射到表),但这意味着要获得联合 View ,您必须更改 C# 服务/存储库以与 EF 实体一起使用添加、更新、删除操作,但告诉类似拉取/读取的方法从联合 View 中获取数据。这可能是您的最佳选择,但比 (B) 涉及更多工作,并且从长远来看也可能影响 Schema。越复杂,风险越大。

关于c# - View 中具有多个(单独的)键的 Entity Framework 关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9010241/

相关文章:

.NET : How to use JIT compiler

.net - Entity Framework EDMX文件大小不成比例大(许多兆字节)

c# - 线程携带重复的字符串对象

c# - 删除两个字符之间的所有内容,只要它们不在其他字符中

c# - .NET:您能否手动指定要包含在自动生成的 WSDL 中的类型?

c# - 使用 String.IsNullOrEmpty(string) 和 Nhibernate 创建动态 Linq 表达式

c# - 搜索实体的所有字段

entity-framework - 如何覆盖 MigratorScriptingDecorator 生成的 SQL 脚本

c# - 在类里面获取路线数据

c# - 展平后缺少 AcroForm 值