axe*_*ter 6 mysql .net-core-2.0 ef-core-2.0
我在 MySql 服务器上使用来自 MySql 的 Sakila 示例数据库。该图如下所示。
重要的表是store、inventory和film表。该是多到许多表和关系连接表是库存表。
我使用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; }
}
Run Code Online (Sandbox Code Playgroud)
存货
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; }
}
Run Code Online (Sandbox Code Playgroud)
电影
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; }
Run Code Online (Sandbox Code Playgroud)
}
我的上下文如下所示:
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");
Run Code Online (Sandbox Code Playgroud)
最后,repo如下所示:
public IEnumerable<Store> GetStores()
{
return _context.Store.
Include(a => a.Inventory).
ToList();
}
Run Code Online (Sandbox Code Playgroud)
问题: 当我从控制器调用此方法以获取商店列表时,我在 Postman 上没有收到任何 json 响应。然而,如果我调试到从控制器返回的列表中,我会找到商店列表。问题是列表包含:store->inventory->film->store->inventory->film->store...等。创建一个循环依赖,填满请求允许的Process内存。
可能的解决方案: 我认为这与以下事实有关:在上下文中,外键都被定义为HasIndex而不是HasKey
entity.HasIndex(e => new { e.StoreId, e.FilmId })
.HasName("idx_store_id_film_id");
Run Code Online (Sandbox Code Playgroud)
当我将它定义为HasKey 时,我收到一个错误:
'从'Rental.Inventory' 到'Inventory.Rental' 与外键属性 {'InventoryId' : int} 的关系不能定位主键 {'StoreId' : byte, 'FilmId' : short} 因为它不兼容。为这种关系配置一个主键或一组兼容的外键属性。
为了回答@hamzas 评论,我确实找到了这个问题的解决方案。我使用 EFCore 通过脚手架(DB First)构建实体和 DBContext。作为最佳实践,您应该使用模型 (Dtos) 来表示客户端的数据。EFCore 非常有帮助,让我们可以根据需要灵活地访问这种 M 到 N 关系。这使我们能够灵活地以我们想要的方式向客户端表示此数据。\n
无论您的用例是什么。您必须将 M 到 N 关系转换为 1 到 N 模型。\n
用例 #1:您想要显示特定商店的所有电影。
\n解决方案
\n步骤#1:创建 StoreDto(模型)
public class StoreDto\n{\n int StoreId { get; set; }\n ICollection<FilmDto> Films { get; set; }\n = new List<FilmDto> ();\n}\n
Run Code Online (Sandbox Code Playgroud)\n第2步:创建 FilmDto
\npublic class FilmDto\n{\n int FilmId { get; set; }\n int StoreId { get; set; }\n string FilmName { get; set; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n步骤#3:使用自动映射器提供映射
\npublic class MappingProfiles : Profile \n{\n public MappingProfiles()\n {\n CreateMap<Store, StoreDto>();\n CreateMap<Film, FilmDto>();\n }\n}\n
Run Code Online (Sandbox Code Playgroud)\n步骤#4:正确查询数据,不幸的是我不再有这个例子来测试这段代码,所以这里是你必须尝试一下的地方
\npublic Store GetFilmsForStore(byte StoreId)\n{\n \n return _context.Store.\n Include(a => a.Inventory).\n ThenInclude(i => i.Film)\n ToList();\n}\n
Run Code Online (Sandbox Code Playgroud)\n在“包含”部分,您只想获取 StoreId == Inverntory.StoreId 的库存条目,然后从结果列表中包含电影对象。\n我希望您能了解其要点。您想要打破多对多的关系,让它们对您的客户来说看起来像是一对多的关系。
\n 归档时间: |
|
查看次数: |
505 次 |
最近记录: |