不能跟踪ASP.Net Core EF M-M实例

时间:2019-02-05 15:59:53

标签: entity-framework asp.net-core

考虑以下错误:

InvalidOperationException: The instance of entity type 'OrderRegion' cannot be tracked because another instance with the key value '[Orderid: 10, RegionId: 1]' is already being tracked...

另外,请考虑以下类(为简洁起见略有删节):

public class Order
…
[Key]
public int Id { get; set; }
…
[Display(Name = "Regions")]
public ICollection<OrderRegion> OrderRegions { get; set; }
[Display(Name = "Stores")]
public ICollection<OrderStore> OrderStores { get; set; }

public class OrderRegion
{
    //[Key]
    public int OrderId { get; set; }
    public Order Order { get; set; }
    //[Key]
    public int RegionId { get; set; }
    public Region Region { get; set; }
}

    public class OrderStore
{
    //[Key]
    public int OrderId { get; set; }
    public Order Order { get; set; }
    //[Key]
    public int StoreId { get; set; }
    public Store Store { get; set; }
}

与之相关的还有创建关联的上下文:

public class MyContext:DbContext
{
    public MyContext(DbContextOptions<AzureOrdersContext> options) : base(options) { }

    public DbSet<Order> Order { get; set; }
    public DbSet<OrderRegion> OrderRegion { get; set; }
    public DbSet<OrderStore> OrderStore { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        …
        modelBuilder.Entity<OrderRegion>()
            .HasKey(nr => new { nr.OrderId, nr.RegionId });
        modelBuilder.Entity<OrderRegion>()
            .HasOne(nr => nr.Order)
            .WithMany(n => n.OrderRegions)
            .HasForeignKey(nr => nr.OrderId);
        modelBuilder.Entity<OrderRegion>()
            .HasOne(nr => nr.Region)
            .WithMany(n => n.OrderRegions)
            .HasForeignKey(nr => nr.RegionId);

        modelBuilder.Entity<OrderStore>()
          .HasKey(nr => new { nr.OrderId, nr.StoreId });
        modelBuilder.Entity<OrderStore>()
            .HasOne(nr => nr.Order)
            .WithMany(n => n.OrderStores)
            .HasForeignKey(nr => nr.OrderId);
        modelBuilder.Entity<OrderStore>()
            .HasOne(nr => nr.Store)
            .WithMany(n => n.OrderStores)
            .HasForeignKey(nr => nr.StoreId);
    }
}

最后,我的“ Edit.cshtml.cs”中抛出了我的错误(被大量剪切):

public async Task<IActionResult> OnPostAsync(int? id, int[] AssignedRegions, int[] AssignedStores)
    {
        if (!ModelState.IsValid)
        {
            return Page();
        }

        var Ordertoupdate = await _context.Order
        .Include(i => i.OrderRegions).ThenInclude(navigationPropertyPath: i => i.Region)
        .Include(i => i.OrderStores).ThenInclude(navigationPropertyPath: i => i.Store)
        .FirstOrDefaultAsync(m => m.Id == id);

       ...

        if (await TryUpdateModelAsync<Web.Models.Order>(
                        Ordertoupdate,
                        "Order",
                        i => i.CreatedOn, 
                        i => i.CreatedBy, 
                        i => i.ModifiedBy, i => i.ExpirationDate,
                        ...))
        {
            UpdateOrderRegions(_context, AssignedRegions, Ordertoupdate);
            UpdateOrderStores(_context, AssignedStores, Ordertoupdate);
            await _context.SaveChangesAsync();
            return RedirectToPage("./Index");
        }
        UpdateOrderRegions(_context, AssignedRegions, Ordertoupdate);
        UpdateOrderStores(_context, AssignedStores, Ordertoupdate);
        PopulateAssignedRegions(_context, Ordertoupdate);
        PopulateAssignedStores(_context, Ordertoupdate);
        return Page();
    }

该错误正在_context.SaveChangesAsync();上引发有任何想法吗?我确定我只是在做一些愚蠢的事情,没有看到简单的解决方法。

根据要求更新以包含UpdateOrderRegions:

public void UpdateOrderRegions (AzureOrdersContext _context, int[] SelectedRegions, Web.Models.Order OrderToUpdate)
    {
        if (SelectedRegions == null)
        {
            OrderToUpdate.OrderRegions = new List<OrderRegion>();
            return;
        }
        var StoreRegionsToDelete= OrderToUpdate.OrderRegions.Where<OrderRegion>(nr => {
            return !SelectedRegions.AsQueryable<Int32>().Contains<Int32>(nr.RegionId);
        });

        StoreRegionsToDelete.ToList().ForEach(r => { OrderToUpdate.OrderRegions.Remove(r); });

        var StoreRegionsToAdd = SelectedRegions.AsQueryable<Int32>().Where<Int32>(regionId => 
            !OrderToUpdate.OrderRegions.Any( nr=> nr.RegionId == regionId) 
        );
        StoreRegionsToAdd.ToList().ForEach(regionId => 
        OrderToUpdate.OrderRegions.Add(new OrderRegion
        {
            OrderId = OrderToUpdate.Id,
            RegionId = regionId
        }));

        ////This is where a different, more frustrating logical error lives but isn't related to my EF error
        ////Attempting to model after: https://github.com/aspnet/Docs/blob/master/aspnetcore/data/ef-rp/intro/samples/cu/Pages/Instructors/InstructorCoursesPageModel.cshtml.cs

        var selectedRegionHS = new HashSet<string>(SelectedRegions);
        var regionOrders = new HashSet<int>(OrderToUpdate.OrderRegions.Select(c => c.Order.Id)); 
        foreach (var thisregion in _context.Region) 
        {
            if (selectedRegionHS.Contains(thisregion.Id.ToString())) 
            {
               if (!regionOrders.Contains(thisregion.Id)) 
                {
                    OrderToUpdate.OrderRegions.Add( 
                       new OrderRegion
                        {
                            OrderId = OrderToUpdate.Id,
                            RegionId = thisregion.Id
                        });
                }
            }

           else
           {
                if (regionOrders.Contains(thisregion.Id))
                {
                    OrderRegion RegionToRemove = OrderToUpdate.OrderRegions.SingleOrDefault(i => i.RegionId == thisregion.Id);
                    _context.Remove(RegionToRemove);
                }
            }
        }
    }

1 个答案:

答案 0 :(得分:2)

当上下文中已经跟踪了一个项目,并且您显式尝试使用相同的键附加新对象时,会发生此问题。

考虑到错误在OrderRegion上,并且此类型具有OrderId / RegionId的复合键,我认为您很可能正在检索OrderRegion并使用相同的OrderId / RegionId组合附加新的OrderRegion。您可能需要检查OrderRegion键是否已经存在或清除订单区域并重新生成列表,以避免发生这种冲突。

我希望这可以为您指明正确的方向。随时提供处理OrderRegion更新的代码,我将尝试进一步提供帮助。