• ABP框架使用(版本3.3.1)


        public class Test : FullAuditedAggregateRootWithUser<Guid, AppUser>
        {
            public string TransactionNumber { get; set; }
    
            public virtual List<TestItem> TestItems { get; set; }
        }
        
        public class TestItem : AuditedEntity
        {
            public Guid TestId { get; set; }
            public Guid ItemId { get; set; }
    
            [ForeignKey("ItemId")]
            public Item Item { get; set; }
            public int Quantity { get; set; }
    
            public virtual List<TestSubItem> TestSubItems { get; set; }
            public override object[] GetKeys()
            {
                return new object[] { TestId,ItemId };
            }
        }
        
            public class TestSubItem : AuditedEntity
        {
            public Guid TestId { get; set; }
            public Guid ItemId { get; set; }
    
            [ForeignKey("TierId")]
            public Tier Tier { get; set; }
            public Guid TierId { get; set; }
            public int Quantity { get; set; }
            public override object[] GetKeys()
            {
                return new object[] { TestId, ItemId , TierId };
            }
        }

    1.当update TestItem的值 , 使用updateaync会报错

    2021-03-27 18:51:43.422 +08:00 [ERR] The instance of entity type 'TestSubItem' cannot be tracked because another instance with the same key value for {'TestId', 'ItemId', 'SubItemId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.

    研究了好久,找不到方法override 这个类 StateManager.

    用下面改变 EntityState 的方法是有时凑效有时不凑效

    _context.Attach(modelPostedToController);
    IEnumerable<EntityEntry> unchangedEntities = _context.ChangeTracker.Entries().Where(x => x.State == EntityState.Unchanged);
    foreach(EntityEntry ee in unchangedEntities){
         ee.State = EntityState.Modified;
    }
    await _context.SaveChangesAsync();

    最后的解决方案是先 remove 再 update, 而且一定不能用 DbContext.SaveChangesAsync()

    要是用aynchu会报错

    [ERR] A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see https://go.microsoft.com/fwlink/?linkid=2097913.

        public class TestItemRepository : EfCoreRepository<DRSDbContext, TestItem>, ITestItemRepository
        {
    
            public TestItemRepository(IDbContextProvider<DRSDbContext> dbContextProvider) : base(dbContextProvider)
            {
    
            }
    
            public Task Save(List<TestItem> entities)
            {
                DbContext.AttachRange(entities);
                DbContext.UpdateRange(entities);
                DbContext.SaveChanges();
                return Task.CompletedTask;
            }
    
            public Task Remove(List<TestItem> entities)
            {
                DbContext.AttachRange(entities);
                DbContext.RemoveRange(entities);
                DbContext.SaveChanges();
                return Task.CompletedTask;
            }
    
        }

    2.当update sub entity的时候,如果sub entity有soft delete的话就会报duplicate key错。

    sub entity不可以有soft delete,才可以update成功。当做法总是会先删除旧的那条,再新增新的那条。所以从last modify time时间来看是不能正确反映真实情况的。

    在abp没有找到DbContext如何触发到ChangeTracker的代码,翻看了下ef core的源代码,用的ReferenceEquals,无从改造大。

    那么就还是在DbContext对ChangeTracker再做一层过滤,回归到Unchanged和Modified的State.

    DbContext

      protected override EntityChangeReport ApplyAbpConcepts()    
    { var changeReport = new EntityChangeReport(); var addList = ChangeTracker.Entries().Where(o => o.State == EntityState.Added).ToList(); var delList = ChangeTracker.Entries().Where(o => o.State == EntityState.Deleted).ToList(); var addListKeys = addList.Select(o => GetEntityId(o.Entity)).ToList(); var delListKeys = delList.Select(o => GetEntityId(o.Entity)).ToList(); var addListHashCodes = addList.Select(o => o.Entity.GetHashCode()).ToList(); var delListHashCodes = delList.Select(o => o.Entity.GetHashCode()).ToList(); var modListKeys = addListKeys.Intersect(delListKeys); var modListHashCodes = addListHashCodes.Intersect(delListHashCodes); foreach (var entry in ChangeTracker.Entries().ToList()) { var keys = GetEntityId(entry.Entity); var hashCodes = entry.Entity.GetHashCode(); if (entry.State == EntityState.Added && modListHashCodes.Contains(hashCodes)) { entry.State = EntityState.Unchanged; } else if (entry.State == EntityState.Added && modListKeys.Contains(keys)) { entry.State = EntityState.Modified; } if (entry.State == EntityState.Deleted && modListKeys.Contains(keys)) continue; ApplyAbpConcepts(entry, changeReport); } return changeReport; }

    这里因为Added entity 的LastModifyTime和Deleted entity 的LastModifyTime不一致,所以要改写sub entity的GetHashCode() 方法,才能判断出两者是UnChanged

        public class ItemTier : AuditedEntity //FullAuditedEntity
        {
            public Guid ItemId { get; set; }
            
            public Guid TierId { get; set; }
    
            [ForeignKey("ItemId")]
            public virtual Item Item { get; set; }
    
            [ForeignKey("TierId")]
            public /*virtual*/  Tier Tier { get; set; }
    
            public bool Allow { get; set; }
    
            public override object[] GetKeys()
            {
                return new object[] { ItemId, TierId };
            }
    
            public override int GetHashCode()
            {
                unchecked // Overflow is fine, just wrap
                {
                    int hash = 17;
                    // Suitable nullity checks etc, of course :)
                    hash = hash * 23 + ItemId.GetHashCode();
                    hash = hash * 23 + TierId.GetHashCode();
                    hash = hash * 23 + Allow.GetHashCode();
                    return hash;
                }
            }
    
        }
  • 相关阅读:
    BZOJ4383 : [POI2015]Pustynia
    BZOJ4382 : [POI2015]Podział naszyjnika
    BZOJ4381 : [POI2015]Odwiedziny
    BZOJ4380 : [POI2015]Myjnie
    BZOJ4378 : [POI2015]Logistyka
    BZOJ3424 : Poi2013 Multidrink
    BZOJ4367 : [IOI2014]holiday假期
    BZOJ4369 : [IOI2015]teams分组
    BZOJ4421 : [Cerc2015] Digit Division
    BZOJ1315 : Ural1557Network Attack
  • 原文地址:https://www.cnblogs.com/sui84/p/14587405.html
Copyright © 2020-2023  润新知