嵌套实体的加载
Loading of nested entities
我在 Entity FrameWork Core 中遇到嵌套实体和一些奇怪行为的问题。
我应该从数据库中加载实体会议 table。会议有多个属性,但只有位置给我带来麻烦。位置存储 a - 位置 ;-) 会议在下面进行了简化。
位置要简单得多,它包含名称、描述、GPS 坐标和地址。见下文
Address 包含一个地址,尽管 class 有更多属性,但在下面进行了简化。
从数据库中检索会议时,一切正常。除非极少数情况下 Name、Description 和 GPSCoordinates 都为 null,否则无论 Address 中存储的任何值如何,Location 都为 null。
如果我将 Name 从 Null 更改为空字符串“”,那么没问题,一切都会按预期加载。
会议、地点和地址的所有值都存储在 flattend 数据库中 table。 table 使用 Fluent Api 配置。另一个 class 课程继承 Meeting 并存储在同一个 table 中 - 因此是鉴别器 - 但它应该没有影响。
为简单起见,减少了以下代码
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);
});
}
我认为这可能是因为您使用的是自有类型。对于拥有的类型,类型的键被定义为其属性的组合。当所有属性都为null时,无法定义key,地址也不会被加载。但是当使用自有类型时,这种行为听起来合乎逻辑。当拥有某物时,当父 属性 不存在时,您假设它不存在。如果不是这样,你应该改变结构。
终于找到解决办法了。事实证明这是 EF Core 中的一个问题,但是在位置上添加导航 属性 并使 属性 成为必需的技巧。
注意它必须在它自己拥有的类型之后配置。
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);
}
还有更多。在寻找解决方案时,我还了解到 Include 在拥有的类型上是多余的。 :-)
我在 Entity FrameWork Core 中遇到嵌套实体和一些奇怪行为的问题。
我应该从数据库中加载实体会议 table。会议有多个属性,但只有位置给我带来麻烦。位置存储 a - 位置 ;-) 会议在下面进行了简化。 位置要简单得多,它包含名称、描述、GPS 坐标和地址。见下文 Address 包含一个地址,尽管 class 有更多属性,但在下面进行了简化。
从数据库中检索会议时,一切正常。除非极少数情况下 Name、Description 和 GPSCoordinates 都为 null,否则无论 Address 中存储的任何值如何,Location 都为 null。
如果我将 Name 从 Null 更改为空字符串“”,那么没问题,一切都会按预期加载。
会议、地点和地址的所有值都存储在 flattend 数据库中 table。 table 使用 Fluent Api 配置。另一个 class 课程继承 Meeting 并存储在同一个 table 中 - 因此是鉴别器 - 但它应该没有影响。
为简单起见,减少了以下代码
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);
});
}
我认为这可能是因为您使用的是自有类型。对于拥有的类型,类型的键被定义为其属性的组合。当所有属性都为null时,无法定义key,地址也不会被加载。但是当使用自有类型时,这种行为听起来合乎逻辑。当拥有某物时,当父 属性 不存在时,您假设它不存在。如果不是这样,你应该改变结构。
终于找到解决办法了。事实证明这是 EF Core 中的一个问题,但是在位置上添加导航 属性 并使 属性 成为必需的技巧。
注意它必须在它自己拥有的类型之后配置。
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);
}
还有更多。在寻找解决方案时,我还了解到 Include 在拥有的类型上是多余的。 :-)