如何使 EF 首先查询上下文,如果未找到,则查询数据库



我有一个程序,它使用 EF 向数据库添加大量数据。其中一个数据是数据库中应该是唯一的记录,所以,我有这个指令:

DataWare.Funcionario funcionario = db.Funcionario.Where(f => f.FunRut.Equals(rut)).FirstOrDefault();

如果未找到"funcionario",则创建一个新对象并按以下方式添加到上下文中:

db.Funcionario.Add(funcionario);

这是在一根蝴蝶里。当在某些迭代中,我们遇到相同的"funcionario"时,上面的 Where 方法返回 null,即使它已经添加到上下文中。

在foreach之后,我保存了对上下文的更改。

我一直在搜索,我发现该方法总是查询数据库,我可以使用 Local 属性来查询上下文中已有的对象,但是,这样我就有 2 个问题。首先,它始终只查询本地实例,因此我需要显式进行 2 次调用,以便在上下文中找不到数据库的情况下查询数据库。第二个问题,也是最糟糕的问题,是当我调用 SaveChanges 到上下文时,它会保存相同记录的许多重复项。我不知道为什么。也许这是由于本地和数据库数据未同步造成的。

任何帮助将不胜感激。

谢谢海梅

编辑:

这是实际场景:我有一个列表<>它实际上为公司员工存储了大量考勤事件。该事件来自考勤设备。

我所说的foreach就是通过该列表的foreach。该事件和工作人员应该在我的数据库中创建,以防它尚不存在。

如果员工不存在,系统会远程调用另一个系统以检索员工信息,然后将该信息保存到我们自己的系统中。如果已添加员工,则应使用该实例,而不是创建新实例。顺便说一下,同一个员工可以在白天生成多个事件。因此,我将该事件添加到我自己的系统中,以关联找到的员工或新创建的员工。

这是 foreach 的完整代码供您参考:

        using (DataWare.SistemasBCIEntities db = new DataWare.SistemasBCIEntities())
        {
            bool exito = false;
            foreach (var log in logs.OrderBy(l => l.EnrollNumber))
            {
                string rut = log.EnrollNumber.ToString();
                DataWare.Funcionario funcionario = db.Funcionario.Where(f => f.FunRut.Equals(rut)).FirstOrDefault();
                if (funcionario == null)
                    funcionario = GetPersonFromZKTime(rut, db);
                if (funcionario != null)
                {
                    // Si ya hay un evento para esa hora y ese funcionario, debe continuar con el siguiente
                    DataWare.Evento evento = db.Evento.Where(e => e.EveFechaHora.Equals(log.Date) && e.Funcionario.FunRut.Equals(rut)).FirstOrDefault();
                    if (evento == null)
                    {
                        exito = true;
                        string tipoEvento = String.Empty;
                        if (log.InOutMode == DataWare.Terminal.InOutModeEnum.Check_In || log.InOutMode == DataWare.Terminal.InOutModeEnum.OT_In || log.InOutMode == DataWare.Terminal.InOutModeEnum.Break_In)
                            tipoEvento = "IN";
                        else
                            tipoEvento = "OUT";
                        evento = new DataWare.Evento()
                        {
                            Funcionario = funcionario,
                            EveFechaHora = log.Date,
                            EveTipo = tipoEvento,
                            EveFechaCreacion = DateTime.Now
                        };
                        db.Evento.Add(evento);
                    }
                }
            }
            db.SaveChanges();
            return exito;
        }

您可能可以检查是否已设置 id,否则将实体状态设置为如下:

foreach(var rut in source.Distinct()) 
{       
    db.Entry(rut).State = rut.Id == 0 ? 
                               EntityState.Added : 
                               EntityState.Modified;
} 

我已经将用于查找记录的字段更改为主键,然后我使用了 EF 的 Find 方法,它按预期工作。

最新更新