efcore2停止多对多关系的循环依赖

jv4diomz  于 2021-06-19  发布在  Mysql
关注(0)|答案(1)|浏览(468)

我正在mysql服务器上使用来自mysql的sakila示例数据库。图表如下所示。

重要的table是商店,库存和电影表。表之间的关系是多对多的,链接器表是inventory表。
我使用efcore2在一个新的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();
}

问题:当我从控制器调用这个方法来获取我不知道的商店列表时´在postman上没有得到任何json响应。但是,如果我调试到从控制器返回的列表中,我会找到存储列表。问题是列表中包含:store->inventory->film->store->inventory->film->store。。。等等。创建一个循环依赖项来填充请求允许的进程内存。
可能的解决方案:我认为这与以下事实有关:在上下文中,两个外键都被定义为hasindex而不是haskey

entity.HasIndex(e => new { e.StoreId, e.FilmId })
                 .HasName("idx_store_id_film_id");

当我将其定义为haskey时,会得到一个错误:
'外键属性为{inventoryid':int}的'rental.inventory'与'inventory.rental'之间的关系不能以主键{storeid':byte,'filmid':short}为目标,因为它不兼容。为此关系配置一个主键或一组兼容的外键属性。'

o3imoua4

o3imoua41#

为了回答@hamzas的评论,我确实找到了解决这个问题的方法。我使用efcore通过scaffolding(db-first)构建实体和dbcontext。作为最佳实践,您应该使用模型(dto)来表示客户机的数据。efcore非常有助于我们灵活地访问这种m-to-n关系。这使我们能够灵活地以我们想要的方式向客户机表示这些数据。
不管你的用例是什么。必须将m到n的关系转换为1到n的模型。
用例1:您希望显示特定商店的所有电影。
解决方案
第1步:创建storedto(模型)

public class StoreDto
{
    int StoreId { get; set; }
    ICollection<FilmDto> Films { get; set; }
       = new List<FilmDto> ();
}

第二步:制作电影

public class FilmDto
{
    int FilmId { get; set; }
    int StoreId { get; set; }
    string FilmName { get; set; }
}

第三步:使用自动Map器提供Map

public class MappingProfiles : Profile 
{
    public MappingProfiles()
    {
        CreateMap<Store, StoreDto>();
        CreateMap<Film, FilmDto>();
    }
}

第四步:正确地查询数据,不幸的是我没有´我们已经没有这个例子来测试这个代码了,所以这里是´我得试一下

public Store GetFilmsForStore(byte StoreId)
{

    return _context.Store.
        Include(a => a.Inventory).
        ThenInclude(i => i.Film)
        ToList();
}

在“include”部分,您只想获取storeid==inverntory.storeid的库存条目,然后从结果列表中包括films对象。我希望你能理解。你想打破你的m对n关系,让他们看起来像你的客户1对m。

相关问题