c# - 在数据库中获取双重数据
问题描述
我从 2 个数据库中提取学生数据。1 个来自可以处理异步调用的在线 SOAP API,1 个来自具有不支持异步的旧服务的本地数据库。
我比较了这些数据库,并通过 EF 将差异写入本地 sqlDB。
问题:
我的 EF DB 中有双重条目。他将正确的数据和数量放入方法中的数组中,但看起来一旦他点击 db.savechanges() 就会跳回几行并再次保存。
我什至不知道这个额外的线程来自哪里。
经过多次尝试解决它,一些代码可能仍然存在。例如,我尝试使用 addrange,但当他尝试添加 FullVarianceList 时出现错误。
public async Task<bool> FullStudentCompare(string date) //format DD/MM/YYYY
{
try
{
//DB context
using (var db = new SchoolDbContext())
{
//GET DATA
//SMT (async)
List<SmtStudent> smtStdudentList = await GetAllSmartschoolStudents();
//Wisa (sync)
//on date, or if emty on current systemdate
List<WisaStudent> wisaList;
if (date == "")
{
wisaList = GetWisaStudentData(DateTime.Now.ToShortDateString());
}
else
{
wisaList = GetWisaStudentData(date);
}
//Flags and props needed for DB entry after compare
bool existsInLocalDb = false;
List<Variance> vList = new List<Variance>();
//Full list to add to DB outside foreach
List<Variance> fullVarianceList = new List<Variance>();
//Full List of new Students to write to DB outside foreach
List<DbStudent> fullStudentList = new List<DbStudent>();
//Compare lists
foreach (WisaStudent wstd in wisaList)
{
//determine correct classCode
string klasCode;
if (wstd.klasgroep.Trim() == "Klasgroep 00")
{
klasCode = wstd.klas.Trim();
}
else
{
klasCode = wstd.klasgroep.Trim();
}
//Create SmtStudent object for compare
SmtStudent tempStd = new SmtStudent(true,
wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
//Find matching SmtStudent
SmtStudent smtStd = smtStdudentList.Find(i => i.Internnummer == wstd.stamboeknummer);
//Find matching Std in local DB
DbStudent dbStd = await db.Students.Where(i => i.Stamboeknummer == wstd.stamboeknummer).FirstOrDefaultAsync();
//if none exists in the local DB create an entity to update and write to DB
if (dbStd == null)
{
dbStd = new DbStudent(wstd.voornaam.Trim(),
wstd.naam.Trim(),
wstd.stamboeknummer.Trim(),
wstd.geslacht.Trim(),
wstd.geboortedatum.Trim(),
wstd.straat.Trim(),
wstd.huisnummer.Trim(),
wstd.busnummer.Trim(),
wstd.postcode.Trim(),
wstd.gemeente.Trim(),
wstd.emailadres.Trim(),
wstd.GSM_nummer.Trim(),
wstd.levensbeschouwing.Trim(),
wstd.coaccountmoedervoornaam.Trim(),
wstd.coaccountmoedernaam.Trim(),
wstd.coaccountmoederemailadres.Trim(),
wstd.coaccountmoederGSM_nummer.Trim(),
wstd.coaccountvadervoornaam.Trim(),
wstd.coaccountvadernaam.Trim(),
wstd.coaccountvaderemailadres.Trim(),
wstd.coaccountvaderGSM_nummer.Trim(),
klasCode,
wstd.loopbaanDatum,
wstd.nationaliteit,
wstd.geboorteGemeente,
wstd.geboorteLand
);
db.Students.Add(dbStd);
fullStudentList.Add(dbStd);
}
else
{
existsInLocalDb = true;
}
if (smtStd == null)
{
//Std doesn't exist in Smt -> New student
dbStd.IsNewStudent = true;
dbStd.ClassMovement = true;
//remove from wisaList
wisaList.Remove(wstd);
}
else
{
//clear vlist from previous iterations
vList.Clear();
//get all properties on the obj, cycle through them and find differences
PropertyInfo[] props = smtStd.GetType().GetProperties();
vList.AddRange(props.Select(f => new Variance
{
Property = f.Name,
ValueA = f.GetValue(smtStd),
ValueB = f.GetValue(tempStd),
Checked = false
})
.Where(v => !v.ValueA.Equals(v.ValueB) && v.ValueB != null)
.ToList());
//If the users allrdy exists in LocalDb delete all previously recorded variances
if (existsInLocalDb)
{
if (db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).FirstOrDefault() != null)
{ //if the student allready exists we will recreate the variancelist, hence deleting all current items first
List<Variance> existingList = db.Variances.Where(j => j.Student.StudentId.Equals(dbStd.StudentId)).ToList();
foreach (Variance v in existingList)
{
db.Variances.Remove(v);
}
}
}
//Add new variances if vList is not empty
if (vList.Count > 0)
{
//Check if KlasCode is a variance -> set classmovement to true
if (vList.Where(i => i.Property == "KlasCode").FirstOrDefault() != null)
{
dbStd.ClassMovement = true;
}
else
{
dbStd.ClassMovement = false;
}
//add the StudentObject to the variance to link them 1-many
foreach (Variance v in vList)
{
v.Student = dbStd;
fullVarianceList.Add(v);
db.Variances.Add(v);
}
}
}
}
//add the full lists of variances and new students to DB
//db.Variances.AddRange(fullVarianceList);
//db.Students.AddRange(fullStudentList);
db.SaveChanges();
return true;
}
}
catch(Exception ex)
{
return false;
}
}
解决方案
有几件事:
重要的是要了解 EF 使用工作单元模式,其中在调用 SaveChanges 之前不会保留对实体的任何更改,这解释了“一旦他点击 db.Savechanges() 他就会跳回”现象。
当您具有一对多关系并将实体集合分配给另一个实体上的导航属性,然后将该父实体添加到 DbContext 时,EF 也会将这些子实体标记为要添加。在您的情况下,将 dbStd 添加到“db.Students.Add(dbStd);”行 在“v.Student = dbStd;”这一行。这很可能是导致您重复的原因。
推荐阅读
- arrays - Ruby 数组条件
- javascript - 如何在图像更改为以后使用之前从图像中获取 src?
- javascript - 如何在数组中找到最大的姓氏
- python - 列出不产生多个敌人 Pygame
- c# - 在通用 Windows 平台 C# 中使用 DeviceWatcher 填充 ComboBox
- excel - Excel VBA用右侧的数据填充左侧的空列,填充列的数量不同?
- c++ - Arduino - 如何将十六进制字节转换为其等效的 ASCII 字符?
- python - Pandas Grouper:如何使用偏移量和原点来获得自定义的每月频率?
- ios - SwiftUI - 如何通过函数制作/生成子视图
- node.js - 如何通过 npm run 使 angular component.ts 脚本独立运行?