如何将多个实体映射到一个表?

10

我想在同一张表中使用两个不同的实体。拥有两个实体的目的是为了限制其中一个实体中的属性数量,因为在某些编辑表单中只能更改其中少数属性。

为了避免将不可编辑的属性隐藏以保留它们的值,我认为创建一个仅包含部分属性的单独实体是个好主意。

因此,我有一个包含所有属性的实体和一个只有部分属性的实体。问题在于,我收到了这个异常:

“实体类型 'ApplicationMapping' 和 'ApplicationMappingFull' 不能共享 'ApplicationMapping' 表,因为它们不在同一类型层次结构中,或者它们之间没有有效的一对一外键关系,匹配主键之间的关系。”

实体配置类如下:

class ApplicationMappingFullConfiguration : EntityTypeConfiguration<ApplicationMappingFull>  
{  
  public ApplicationMappingFullConfiguration()  
  {  
    ToTable("ApplicationMapping");  
    HasKey(p => p.Id);  
  }  
}  

class ApplicationMappingConfiguration : EntityTypeConfiguration<ApplicationMapping>  
{  
  public ApplicationMappingConfiguration()  
  {  
    ToTable("ApplicationMapping");  
    HasKey(p => p.Id);  
  }  
}

我怎样才能实现我想做的事情?有没有更好/更简单的方法来做到这一点?

谢谢!


ApplicationMappingFull 继承自 ApplicationMapping 吗?您能否将这些类的代码添加到您的问题中? - Henk Mollema
@HenkMollema 不,实体之间没有继承关系。它们是独立的实体,一个拥有表中的所有字段,另一个只有几个字段。 - Stian
只需使用两个单独的视图模型,它们都映射回同一实体即可。 - dotjoe
那么在这里,ViewModel方法最适合。 - Henk Mollema
4个回答

4
我建议将一个实体映射到该表,但创建两个“视图”实体,其中只包含表单需要的属性。
这些视图实体可以包含将输入的数据映射回基础实体的方法。

谢谢,我会尝试这个方法。 - Stian
你可能想要谷歌一下 MVVM(Model-View-ViewModel)模式,因为这就是你在这里看到的。 - Paddy

3
看起来您正在寻找TPH(表格继承层次结构)。这是一种关系继承模式,其中一个类及其所有子类共享同一个表,并且被Entity Framework原生支持。实际上,如果您只是让一个实体继承另一个实体,Entity Framework默认会使用该模式。您无需做任何特殊处理。
但是,有一个条件:由于基类上的属性必须足够独立,以便能够成功将行保存到数据库中,因此您的所有子类属性在数据库级别上都必须是可选的。您总是可以通过前端用户界面强制要求一个或多个属性为必填项。
更新:
针对我下面的评论进行扩展,如果您只是想从表中返回数据子集,那么您已经拥有了所有需要的工具。您不需要两个单独的实体,只需要一个实体(在本例中为您的ApplicationMappingFull类),然后您可以使用LINQ返回您所需的列即可。
db.ApplicationMappingFulls.Select(m => new ApplicationMappingViewModel
    {
        SomeProperty = m.SomeProperty,
        OtherProperty = m.OtherProperty
    });

在幕后,EF会发出一个查询,只选择SomePropertyOtherProperty列,因为这就是所需的。您的视图模型不会与EF连接;它只是一个类来保存由EF返回的数据。

嘿,我尝试使用继承,但现在我得到一个异常,说我需要一个“鉴别器”列。我理解这个列的目的,但基类和子类之间没有区别。我只想能够从表中检索一行,并用仅有几列的对象表示它,在另一种情况下获取具有所有列的相同行。数据在两种情况下都是相同的,并且表中的所有行都是相同类型的。 - Stian
如果你只是想从数据库中显示少量信息,就不应该处理两个实体。使用 LINQ 可以选择你想要的列,EF 实际上会在数据库层面上发出相应的语句。然后你可以返回一个仅包含这些属性的匿名对象,或者更好地将它映射到一个视图模型。 - Chris Pratt

1
另一种选择是让一个类继承另一个类,并隐藏或禁用您不希望进行编辑的字段。
例如...
class Full {
  public string ValueA {get;set;}
}

class Limited : Full {
  public new string ValueA {get; private set;}
}

这个解决方案可能并不是最好的选择,但你可以尝试使用它。

-1

你的问题已经有了答案。

The entity types 'ApplicationMapping' and 'ApplicationMappingFull' cannot share table 'ApplicationMapping'
当您将实体类型映射到表时,您正在为表定义架构。正如您所说,您有一个具有所有属性的实体和一个只有部分属性的实体。当您将实体映射到表时,需要将表的所有列映射到它们。
因此,在一行中,“这是不可能的”。 要解决您的问题,您可以像Paddy建议的那样执行操作。否则,您可以创建一个带有最少所需属性的基类,然后扩展该类并添加其余属性。在将模型传递给视图时,请传递基类对象。但是,在从数据库中获取记录时,您可以使用扩展类对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接