如何映射具有实体引用的值类型
本文关键字:引用 实体 类型 何映射 映射 | 更新日期: 2023-09-27 18:19:36
实体框架中的映射出现问题。
我有以下类别(简化):
public class Building
{
public int ID { get; set; }
// *.. snip..* other properties
public Location Location { get; private set; }
}
public class Location
{
public string Street {get; set;}
public Country country {get; set}
}
public class Country
{
public int ID { get; set; }
public string Name { get; set; }
}
Building和Country是实体,它们保存在数据库中。位置是一种值类型,应映射到与Building相同的表中。
然而,当我以这种方式映射它时,实体框架也想将Location映射到一个表,并抱怨它没有Key。我不想给它钥匙,因为它属于大楼,根本不应该是一个实体。
我见过一些变通方法,说你需要把Country放在Building类上,但这感觉不太好(而且在语义上完全错误)。
我使用的是实体框架5
自从实体框架核心2发布以来,现在可以使用拥有的实体来实现这一点。
您的配置看起来像:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// ...
modelBuilder.Entity<Building>().OwnsOne(x => x.Location);
modelBuilder.Entity<Location>().HasOne(x => x.Country);
// ...
}
这样,Location
类的属性将成为Building
类映射到的表的一部分。这意味着您将只有Building
和Country
类的表,而Building
表将有一个指向Country
表的外键。
我知道你已经很久没有发布这个问题了,但我认为这个答案可能对遇到这个问题的人有帮助。
在我看来,实体框架不应该允许这样的情况。
我知道您不认为Location是一个实体,但向复杂类型添加实体引用似乎也不是一个可靠的方法。一座建筑与一个国家的关系是非常直接的。一座建筑属于一个国家。因此,一个建筑模型应该包括一个国家id。你希望映射什么?
如果您希望Building表只有三列ID, Street, CountryId
,并且您仍然希望保存Location模型,那么您应该使用以下复杂类型。
public class Location
{
public string Street {get; set;}
public int countryId {get; set}
}
但是,如果您希望您的Building表包含模型Country中的所有字段,那么这可能会导致一些棘手的情况,例如如果您想向Country模型添加新字段,或者如果您想根据新的业务案例向Country模型添加其他复杂类型或实体,会发生什么情况。
这些情况会扰乱关系概念,并在没有任何有意义的理由的情况下使您的结构过于复杂。(当然在我看来)
您可以用[NotMapped]属性标记Building类中的Location属性。
using System.ComponentModel.DataAnnotations.Schema;
public class Building
{
[NotMapped]
public Location Location { get; private set; }
}
希望这能解决你的问题!