我正在MySql服务器上使用来自MySql的Sakila示例数据库。该图如下所示。
重要的表格是商店,库存和电影表格。表之间是多对多关系,链接器表是库存表。
我使用 EFCore 2 在新的dotnetcore项目中搭建了该数据库。 我正在尝试获取商店的列表及其电影的列表。
实体的定义如下:
商店
public class Store
{
public Store()
{
Customer = new HashSet<Customer>();
Inventory = new HashSet<Inventory>();
Staff = new HashSet<Staff>();
}
public byte StoreId { get; set; }
public byte ManagerStaffId { get; set; }
public short AddressId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Address Address { get; set; }
public Staff ManagerStaff { get; set; }
public ICollection<Customer> Customer { get; set; }
public ICollection<Inventory> Inventory { get; set; }
public ICollection<Staff> Staff { get; set; }
}
库存
public partial class Inventory
{
public Inventory()
{
Rental = new HashSet<Rental>();
}
public int InventoryId { get; set; }
public short FilmId { get; set; }
public byte StoreId { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Film Film { get; set; }
public Store Store { get; set; }
public ICollection<Rental> Rental { get; set; }
}
电影
public partial class Film
{
public Film()
{
FilmActor = new HashSet<FilmActor>();
FilmCategory = new HashSet<FilmCategory>();
Inventory = new HashSet<Inventory>();
}
public short FilmId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public short? ReleaseYear { get; set; }
public byte LanguageId { get; set; }
public byte? OriginalLanguageId { get; set; }
public byte RentalDuration { get; set; }
public decimal RentalRate { get; set; }
public short? Length { get; set; }
public decimal ReplacementCost { get; set; }
public string Rating { get; set; }
public string SpecialFeatures { get; set; }
public DateTimeOffset LastUpdate { get; set; }
public Language Language { get; set;
public Language OriginalLanguage { get; set; }
public ICollection<FilmActor> FilmActor { get; set; }
public ICollection<FilmCategory> FilmCategory { get; set; }
public ICollection<Inventory> Inventory { get; set; }
}
我的上下文如下所示:
modelBuilder.Entity<Inventory>(entity =>
{
entity.ToTable("inventory", "sakila");
entity.HasIndex(e => e.FilmId)
.HasName("idx_fk_film_id");
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
最后,回购如下所示:
public IEnumerable<Store> GetStores()
{
return _context.Store.
Include(a => a.Inventory).
ToList();
}
问题: 当我从Controller调用此方法以获取存储列表时,Postman上没有任何json响应。但是,如果我调试从Controller返回的列表,则会找到存储列表。 问题在于该列表包含: store-> inventory-> film-> store-> inventory-> film-> store ...等创建循环依赖项,以填充请求的允许进程内存。
可能的解决方案: 我认为这与以下事实有关:在 Context 上,两个外键均被定义为 HasIndex 而不是 HasKey
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
当我将其定义为 HasKey 时,我会收到错误消息:
'从'Rental.Inventory'到'Inventory.Rental'的关系 外键属性{'InventoryId':int}无法定位主键 键{'StoreId':字节,“ FilmId”:短},因为它不兼容。 配置主键或一组兼容的外键 关系的属性。”
答案 0 :(得分:1)
要回答@hamzas评论,我确实找到了解决此问题的方法。我使用EFCore通过脚手架(数据库优先)构建实体和DBContext。作为最佳实践,您应该使用模型(Dtos)代表客户端的数据。 EFCore对于帮助我们灵活地访问这种M对N关系非常有帮助。这使我们能够灵活地根据需要向客户表示此数据。
无论您使用哪种情况。您必须将M对N的关系转换为1对N的模型。
用例1:您要显示特定商店的所有电影。
解决方案
步骤1:您创建一个StoreDto(模型)
public class StoreDto
{
int StoreId { get; set; }
ICollection<FilmDto> Films { get; set; }
= new List<FilmDto> ();
}
步骤2:创建FilmDto
public class FilmDto
{
int FilmId { get; set; }
int StoreId { get; set; }
string FilmName { get; set; }
}
步骤3:您提供了带有自动映射器的映射
public class MappingProfiles : Profile
{
public MappingProfiles()
{
CreateMap<Store, StoreDto>();
CreateMap<Film, FilmDto>();
}
}
第4步::正确查询数据,不幸的是,我没有这个示例了,无法测试此代码,因此这里是您必须尝试的地方
public Store GetFilmsForStore(byte StoreId)
{
return _context.Store.
Include(a => a.Inventory).
ThenInclude(i => i.Film)
ToList();
}
在“包含”部分上,您只想获取其中StoreId == Inverntory.StoreId的Inventory条目,然后从结果列表中包含Films Object。 希望您能理解。您想破坏您的m到n关系,并使其与客户之间的关系从1到m。