我有一个Save
对象,它有几个关联的集合。对象的总大小如下:
对象之间的关系可以从这个Map中推断出来,并且看起来在数据库中被正确地表示出来。查询也工作得很好。
modelBuilder.Entity<Save>().HasKey(c => c.SaveId).HasAnnotation("DatabaseGenerated",DatabaseGeneratedOption.Identity);
modelBuilder.Entity<Save>().HasMany(c => c.Families).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Countries).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Provinces).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Save>().HasMany(c => c.Pops).WithOne(x => x.Save).HasForeignKey(x => x.SaveId);
modelBuilder.Entity<Country>().HasOne(c => c.Save);
modelBuilder.Entity<Country>().HasMany(c => c.Technologies).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.CountryId});
modelBuilder.Entity<Country>().HasMany(c => c.Players).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.CountryId});
modelBuilder.Entity<Country>().HasMany(c => c.Families).WithOne(x => x.Country).HasForeignKey(x => new {x.SaveId, x.OwnerId});
modelBuilder.Entity<Country>().HasMany(c => c.Provinces).WithOne(x => x.Owner);
modelBuilder.Entity<Country>().HasKey(c => new { c.SaveId, c.CountryId });
modelBuilder.Entity<Family>().HasKey(c => new { c.SaveId, c.FamilyId });
modelBuilder.Entity<Family>().HasOne(c => c.Save);
modelBuilder.Entity<CountryPlayer>().HasKey(c => new { c.SaveId, c.CountryId, c.PlayerName });
modelBuilder.Entity<CountryPlayer>().HasOne(c => c.Country);
modelBuilder.Entity<CountryPlayer>().Property(c => c.PlayerName).HasMaxLength(100);
modelBuilder.Entity<CountryTechnology>().HasKey(c => new { c.SaveId, c.CountryId, c.Type });
modelBuilder.Entity<CountryTechnology>().HasOne(c => c.Country);
modelBuilder.Entity<Province>().HasKey(c => new { c.SaveId, c.ProvinceId });
modelBuilder.Entity<Province>().HasMany(c => c.Pops).WithOne(x => x.Province);
modelBuilder.Entity<Province>().HasOne(c => c.Save);
modelBuilder.Entity<Population>().HasKey(c => new { c.SaveId, c.PopId });
modelBuilder.Entity<Population>().HasOne(c => c.Province);
modelBuilder.Entity<Population>().HasOne(c => c.Save);
我从一个文件中解析整个save
,所以我不能一个一个地添加所有集合。解析后,我得到了一个Save
及其所有关联的集合,总共有80k个对象,其中没有一个在数据库中出现。
然后,当我调用dbContext.Add(save)
时,它需要大约44秒来处理,RAM使用量从100mb上升到大约700mb。
然后,当我调用dbContext.SaveChanges()
时(我也尝试了EF扩展中的常规BulkSaveChanges()
方法,没有明显的区别),它需要额外的60s,RAM使用率高达1.3Gb。
这是怎么回事?为什么这么长时间和这么多的内存使用?实际上传到数据库只需要大约最后5秒钟。
PS:我也试过禁用变化检测,没有效果。
PS2:实际使用情况和注解中要求的完整代码:
public class HomeController : Controller
{
private readonly ImperatorContext _db;
public HomeController(ImperatorContext db)
{
_db = db;
}
[HttpPost]
[RequestSizeLimit(200000000)]
public async Task<IActionResult> UploadSave(List<IFormFile> files)
{
[...]
await using (var stream = new FileStream(filePath, FileMode.Open))
{
var save = ParadoxParser.Parse(stream, new SaveParser());
if (_db.Saves.Any(s => s.SaveKey == save.SaveKey))
{
response = "The save you uploaded already exists in the database.";
}
else
{
_db.Saves.Add(save);
}
_db.BulkSaveChanges();
}
[...]
}
}
3条答案
按热度按时间jhdbpxl91#
从nugets下载EFCore.BulkExtensions
删除“_db.BulkSaveChanges();“并替换为“_db.Saves.Add(保存);“与此代码
2lpgd9682#
编辑:1.确保问题不在数据库上。
执行您自己的命令以查看它的运行速度。
1.通过为每个工作单元使用新上下文来保持活动上下文图较小,同时尝试关闭AutoDetechChangesEnabled
3.将许多命令成批处理在一起
这是一篇关于实体框架和慢速批量INSERT的好文章
4dc9hkyq3#
我建议您看一下N.EntityFrameworkCore.Extension。它是EFCore 6.0.8+的批量扩展框架
https://www.nuget.org/packages/N.EntityFrameworkCore.Extensions
一旦你安装了nuget包,你就可以直接在DbContext示例上使用BulkInsert()方法。它支持BulkDelete、BulkInsert、BulkMerge等等。
批量删除()
大量插入()