【发布时间】:2021-10-21 00:20:11
【问题描述】:
我正在开发一个用于在学校订餐的应用。这需要最终用户为不同类型(总秘书处、教师、学生......)添加帐户。
为此我制作了一个可靠的界面,但添加 1000 名学生需要 111 秒,因为一次插入需要经过所有查询。
这是插入的代码:
public async Task<List<FullPupil>> AddPupilAccountsBySchoolId(List<FullPupil> pupils, string schoolId, string password, string hashedPassword, Types type) {
foreach (FullPupil pupil in pupils) {
Accounts checkAccount = await _context.Accounts.FirstOrDefaultAsync(a => a.Email == pupil.Email);
if (checkAccount == null) {
Accounts newAccount = new Accounts() {
Email = pupil.Email,
FirstTime = true,
FirstTimePassword = password,
Password = hashedPassword,
Name = pupil.Name,
SurName = pupil.SurName,
EmailSend = false,
};
await _context.Accounts.AddAsync(newAccount);
checkAccount = newAccount;
}
AccountsTypes checkAccountsTypes = await _context.AccountsTypes.FirstOrDefaultAsync(a => a.AccountId == checkAccount.AccountId && a.TypeId == type.TypeId);
if (checkAccountsTypes == null) {
AccountsTypes accountsTypes = new AccountsTypes() {
AccountId = checkAccount.AccountId,
TypeId = type.TypeId,
};
await _context.AccountsTypes.AddAsync(accountsTypes);
}
Pupils checkPupil = await _context.Pupils.FirstOrDefaultAsync(a => a.AccountId == checkAccount.AccountId);
if (checkPupil == null) {
Pupils newPupil = new Pupils() {
AccountId = checkAccount.AccountId,
ClassId = Guid.Parse(pupil.Class[0].Id),
CodeId = Guid.Parse(pupil.Code[0].Id),
ModifiedDate = DateTime.Now,
};
await _context.Pupils.AddAsync(newPupil);
} else {
checkPupil.ModifiedDate = DateTime.Now;
}
pupil.AccountId = checkAccount.AccountId;
}
await _context.SaveChangesAsync();
return pupils;
}
(我知道所有账号都会有相同的密码,这只是为了测试目的)
这是使用的数据库结构:
(Pupils 中的 classId 与学校的唯一班级相关联)
一个帐户可以具有多个功能,也可以在多个学校具有相同功能,例如:一位教师可以是多所学校的教师,同时也是另一所学校的家长。 (AccountsTypes 是 Accounts 和 Types 之间的多对多关系)
因此,插入需要检查该帐户是否已经存在,如果不存在,则添加它,否则什么也不做,继续检查它是否已经是这所学校的学生,如果不是, 添加它,否则什么都不做等等。
我想到了一个解决方案,只需添加所有内容,如果它已经存在,则无需先检查就对其进行更新,但我找不到任何有关如何执行此操作的信息。
那么我该如何优化它,这样它就不会花费很长时间,也不必检查它是否已经存在,并且可能将其插入到一个 addAsync 中,以便将其添加到所有相关表中?
这也需要非常可靠,以免失败。
【问题讨论】:
-
EF 不是为批量操作而设计的。如果你同意,我将展示如何使用第三方扩展来做到这一点。
-
@SvyatoslavDanyliv 如果你能推荐一个第三方扩展,我可以免费使用和商业用途,而不需要让用户知道我正在使用这个扩展?
-
当然。麻省理工学院许可证。
-
看看entityframework-extensions.net(非常非常好但是需要付费),或者github.com/borisdj/EFCore.BulkExtensions
-
我尝试了 borisdj 的 EFCore.BulkExtension 但有关关系的文档不是很好,我无法使其工作(它工作但它没有更新相关表中的 guid,外国 id 总是 00000 ......是什么让它崩溃了)。
标签: .net asp.net-web-api entity-framework-core insert bulkinsert