插入嵌套对象 EF Core 5

Posted

技术标签:

【中文标题】插入嵌套对象 EF Core 5【英文标题】:Inserting Nested Objects EF Core 5 【发布时间】:2021-10-19 03:25:41 【问题描述】:

我有以下实体:

    批次 样品 样品容器 样本测试

一个批次包含许多样本。一个样本包含许多SampleContainers 和许多SampleTests

我正在尝试复制批处理并插入数据库。

尝试 #1:在存储库中获取函数:

return await context.Set<TEntity>().FindAsync(id);

控制器:

var coc = await repository.Get(batchId);

coc.BatchStatusId = (int)Enums.BatchStatus.InProgress;
coc.IsTemplate = false;
coc.Id = 0;
        
var b = await repository.Add(coc);

这里只复制了批次对象,但没有复制/插入相关的样本和容器。

尝试 #2:我将 Get 函数更改如下:

public async override Task<Batch> Get(int id)

    return await context.Set<Batch>()
            .Include(p => p.Samples)
            .FirstOrDefaultAsync(p => p.Id == id);

这一次批次被复制了,但是样本、容器和测试都用新的 batchId/FK 更新(我希望它们都被复制)。

尝试#3:按照this,我实现如下:

public async Task<int> DuplicateBatch([FromBody]int batchId)

        try
        
            var coc = await repository.Get(batchId);

            coc.BatchStatusId = (int)Enums.BatchStatus.InProgress;
            coc.IsTemplate = false;
            coc.Id = 0;

            var samples = coc.Samples.ToList();
            repository.DetachEntity(coc);

            var b = await repository.Add(coc);
            
            var allSampleTests = await sampleTestRepo.GetAll();
            var allSampleContainers = await sampleContainersRepo.GetAll();

            var sampletests = from st in allSampleTests
                              join s in samples on st.SampleId equals s.Id
                              select st;
            var sampleContainers = from sc in allSampleContainers
                                   join s in samples on sc.SampleId equals s.Id
                                   select sc;

            sampleRepo.DetachEntities(samples);
            
            sampleTestRepo.DetachEntities(sampletests.ToList());
            sampleContainersRepo.DetachEntities(sampleContainers.ToList());

            foreach (var s in samples) 
            
                s.BatchId = b.Id;

                var sample = await sampleRepo.Add(s);

                foreach (var st in sampletests)
                
                    st.SampleId = sample.Id;
                    await sampleTestRepo.Add(st);
                

                foreach(var sc in sampleContainers)
                
                    sc.SampleId = sample.Id;                        
                    await sampleContainersRepo.Add(sc);
                
                            
            
            return 1;
        
        catch (Exception ex)
        
            return 0;
        
 

这一次我一达到分离功能就面临以下异常:

"属性 'Batch.Id' 是键的一部分,因此无法修改 或标记为已修改。更改现有实体的委托人 使用标识外键,首先删除依赖项并调用 'SaveChanges',然后将依赖项与新的关联 校长。”

【问题讨论】:

【参考方案1】:

这就是我做的,大部分是不言自明的。

public async Task<int> DuplicateBatch([FromBody]int batchId)
    
        try
        
            //STEP 1: Fetch the entities
            var coc2 = await repository.Get(batchId);
            var samples = coc2.Samples.ToList();

            var allSampleTests = await sampleTestRepo.GetAll();
            var allSampleContainers = await sampleContainersRepo.GetAll();

            var sampletests = samples.SelectMany(st => st.SampleTests).ToList();
            var samplecontainers = samples.SelectMany(st => st.SampleContainers).ToList();

            //STEP 2: Detach
            var coc = repository.DetachEntity(coc2);
            var samplesDetached = sampleRepo.DetachEntities(samples);
            var sampleTestsDetached = sampleTestRepo.DetachEntities(sampletests);
            var sampleContianersDetached = sampleContainersRepo.DetachEntities(samplecontainers);

            //STEP 3: Update object
            coc2.BatchStatusId = (int)Enums.BatchStatus.InProgress;
            coc2.IsTemplate = false;
            


            var b = await repository.Add(coc);

            return 1;
        
        catch (Exception ex)
        
            return 0;
        

    

【讨论】:

以上是关于插入嵌套对象 EF Core 5的主要内容,如果未能解决你的问题,请参考以下文章

EF Core 慢速批量插入(~80k 行)

EF Core 错误地为 Array 执行多次插入

EF Core (< 5.0) HasComputedColumnSql - 在插入/更新或 SQL Server/AzureSQL 上的每个查询上计算?

如何避免在 EF Core 中插入后选择插入的实体?

EF Core Seeding 机制不插入数据

EF6 vs Entity Framework Core:插入实体而不将主键(身份)重置为零