C# 加载嵌套实体
我有一个关于嵌套实体和实体框架核心中一些奇怪行为的问题 我应该从数据库表加载实体会议。会议有多个属性,但只有位置会给我带来麻烦。位置存储a-位置;-)会议简化如下。 位置更简单,它包含名称、描述、GPSCoordinates和地址。见下文 Address保存一个地址,尽管该类有更多属性,但下面对其进行了简化 从Db检索会议时,一切都很好。除非出现名称、描述和GPSCoordinates都为null的罕见情况,否则无论存储在Address中的任何值如何,Location都为null 如果我将Name从Null更改为空字符串“”,则没有问题,所有内容都会按预期加载 会议、地点和地址的所有值都存储在平坦的数据库表中。该表是使用Fluent Api配置的。另一个类课程继承了Meeting并存储在同一个表中-因此是decriminator-但它应该没有影响 为了简单起见,下面的代码被简化了C# 加载嵌套实体,c#,asp.net-core,entity-framework-core,ef-fluent-api,owned-types,C#,Asp.net Core,Entity Framework Core,Ef Fluent Api,Owned Types,我有一个关于嵌套实体和实体框架核心中一些奇怪行为的问题 我应该从数据库表加载实体会议。会议有多个属性,但只有位置会给我带来麻烦。位置存储a-位置;-)会议简化如下。 位置更简单,它包含名称、描述、GPSCoordinates和地址。见下文 Address保存一个地址,尽管该类有更多属性,但下面对其进行了简化 从Db检索会议时,一切都很好。除非出现名称、描述和GPSCoordinates都为null的罕见情况,否则无论存储在Address中的任何值如何,Location都为null 如果我将Nam
public class Meeting : BaseEntity<long>
{
public string Name { get; set; }
public Location Location { get; set; }
}
public class Location
{
public string Name { get; set; }
public string Description { get; set; }
public PostalAddress Address { get; set; }
public Point GpsCoordinates { get; set; }
}
public class PostalAddress
{
public string StreetAddress1 { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
}
Meeting meet = context.meetDbSet.Include(p=>p.Location).ThenInclude(p=>p.Address).FirstOrDefault();
public void Configure(EntityTypeBuilder<Meeting> builder)
{
builder
.ToTable("Meetings")
.HasKey(p => p.Id);
builder
.HasDiscriminator<string>("Meeting_Descriminator")
.HasValue<Meeting>("")
.HasValue<Course>("Course");
builder
.OwnsOne(p => p.Location, location =>
{
location
.Property(p => p.Name)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
location
.Property(p => p.Description)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
location
.OwnsOne(p => p.Address, postaladdress =>
{
postaladdress
.Property(p => p.StreetAddress1)
.HasColumnName("StreetAddress1")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.ZipCode)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.City)
.HasColumnName("City")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.Country)
.HasColumnName("Country")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
});
location
.Property(p => p.GpsCoordinates)
.HasColumnType("geography")
.IsRequired(false);
});
}
公共类会议:BaseEntity
{
公共字符串名称{get;set;}
公共位置位置{get;set;}
}
公共类位置
{
公共字符串名称{get;set;}
公共字符串说明{get;set;}
公共邮政地址{get;set;}
公共点GpsCoordinates{get;set;}
}
公务舱邮品
{
公共字符串StreetAddress1{get;set;}
公共字符串ZipCode{get;set;}
公共字符串City{get;set;}
公共字符串国家{get;set;}
}
Meeting meet=context.meetDbSet.Include(p=>p.Location)。然后Include(p=>p.Address)。FirstOrDefault();
公共void配置(EntityTypeBuilder)
{
建设者
.ToTable(“会议”)
.HasKey(p=>p.Id);
建设者
.HasDiscriminator(“会议描述者”)
.HasValue(“”)
.HasValue(“课程”);
建设者
.OwnsOne(p=>p.Location,Location=>
{
位置
.Property(p=>p.Name)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
位置
.Property(p=>p.Description)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
位置
.OwnsOne(p=>p.地址,邮资=>
{
邮资
.Property(p=>p.StreetAddress1)
.HasColumnName(“StreetAddress1”)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.ZipCode)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.City)
.HasColumnName(“城市”)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.Country)
.姓名(“国家”)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
});
位置
.Property(p=>p.GpsCoordinates)
.HasColumnType(“地理”)
.i被要求(虚假);
});
}
我认为这可能是因为您使用的是自有类型。对于拥有的类型,类型的键定义为其属性的组合。当所有属性都为null时,无法定义键,因此也不会加载地址。但当使用自有类型时,这种行为听起来是合乎逻辑的。当某事物被拥有时,如果父属性不存在,则假定该事物不存在。如果不是这样,你应该改变结构。我终于找到了解决方案。事实证明,这在EF Core中是一个问题,但在location上添加导航属性并使该属性成为必需的属性就成功了
请注意,它必须在自己拥有的类型之后进行配置
public void Configure(EntityTypeBuilder<Meeting> builder)
{
builder
.ToTable("Meetings")
.HasKey(p => p.Id);
builder
.HasDiscriminator<string>("Meeting_Descriminator")
.HasValue<Meeting>("")
.HasValue<Course>("Course");
builder
.OwnsOne(p => p.Location, location =>
{
location
.Property(p => p.Name)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
location
.Property(p => p.Description)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
location
.OwnsOne(p => p.Address, postaladdress =>
{
postaladdress
.Property(p => p.StreetAddress1)
.HasColumnName("StreetAddress1")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.ZipCode)
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.City)
.HasColumnName("City")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
postaladdress
.Property(p => p.Country)
.HasColumnName("Country")
.HasColumnType("nvarchar(max)")
.IsRequired(false);
});
location
.Property(p => p.GpsCoordinates)
.HasColumnType("geography")
.IsRequired(false);
});
builder
.Navigation(p => p.Location)
.IsRequired(true);
}
public void配置(EntityTypeBuilder)
{
建设者
.ToTable(“会议”)
.HasKey(p=>p.Id);
建设者
.HasDiscriminator(“会议描述者”)
.HasValue(“”)
.HasValue(“课程”);
建设者
.OwnsOne(p=>p.Location,Location=>
{
位置
.Property(p=>p.Name)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
位置
.Property(p=>p.Description)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
位置
.OwnsOne(p=>p.地址,邮资=>
{
邮资
.Property(p=>p.StreetAddress1)
.HasColumnName(“StreetAddress1”)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.ZipCode)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.City)
.HasColumnName(“城市”)
.HasColumnType(“nvarchar(最大)”)
.i被要求(虚假);
邮资
.Property(p=>p.Country)
哈斯科先生