首页 > 解决方案 > 在数据库中获取双重数据

问题描述

我从 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;
    }
}

标签: c#asp.net-mvcentity-framework

解决方案


有几件事:

  1. 重要的是要了解 EF 使用工作单元模式,其中在调用 SaveChanges 之前不会保留对实体的任何更改,这解释了“一旦他点击 db.Savechanges() 他就会跳回”现象。

  2. 当您具有一对多关系并将实体集合分配给另一个实体上的导航属性,然后将该父实体添加到 DbContext 时,EF 也会将这些子实体标记为要添加。在您的情况下,将 dbStd 添加到“db.Students.Add(dbStd);”行 在“v.Student = dbStd;”这一行。这很可能是导致您重复的原因。


推荐阅读