Entity Framework: 使用本地对象设置导航属性(尚未保存到数据库)
Entity Framework: Set navigation property with a local object (not saved to the database yet)
我正在使用 Entity Framework 版本 6,需要在很短的时间内将数千个对象批量插入数据库。
因此我将 DbContext.Configuration.AutoDetectChangesEnabled
更改为 false 并且仅在添加了许多项后才使用 SaveChanges
。
这个实体,我们称它为 Person
,有一个导航 属性 到它自己,例如。 G。 Supervisor
.
现在我想将一个人添加到数据库中,并想用迭代前刚刚添加到上下文(只是本地,不在数据库中)的主管填充导航 属性。
由于性能原因,我只是在 200 万人之后调用 SaveChanges()。如果我在 SaveChanges
之后查看数据库,列 Supervisor
始终为 NULL。如何添加导航属性?
奇怪的是,我的实体模型有四个导航属性,分别名为 Supervisor1
、Supervisor2
、Supervisor11
和 Supervisor3
。为什么实体模型为一个数据库约束创建四个导航属性?
详细解释我的问题:这是我的
database structure. EntityFramework creates this model.
有一个循环来处理来自 csv 文件的数据:
db.DbContext.Configuration.AutoDetectChangesEnabled = false; // for performance
///...
while (!parser.EndOfData)
{
// process data from a csv file with a name and a supervisorId
db.AddNewPerson(name, supervisorId);
}
db.SaveChanges();
db.DbContext.Configuration.AutoDetectChangesEnabled = true;
这是数据访问层方法:
public void AddNewPerson(string name, long? supervisorId)
{
var dbSetPerson = dbContext.Set<Person>();
var newPerson = new Person(name);
dbSetPerson.Add(newPerson);
if (supervisorId != null)
{
var supervisor = dbSetPerson.Local.FirstOrDefault(x => x.PersonId == supervisorId); // first look if the supervisor was just processed in this loop
if (supervisor == null)
supervisor = dbSetPerson.FirstOrDefault(x => x.PersonId == supervisorId); // if the was no person found look in the database
if (supervisor != null)
newPerson.Person2 = supervisor;
}
}
提前感谢您的帮助!
我认为你的问题是,实体在这个阶段没有存储到数据库中,EF(代理)不知道它。您可以做的是在调用 StoreChanges():
之后附加它
yourContext.Persons.Attach(justAddedPerson);
但是当你添加一些代码时,我可以给出更具体的答案。
更新
根据您的编辑(我猜 ID 是整数而不是自动创建的)我建议如下:
var persons = new List<Person>();
while (!parser.EndOfData)
{
var person = new Person { Name = parser... }
person.SupervisorId = parser...
list.Add(person);
}
dbSet.AddRange(persons);
dbContext.SaveChanges();
先做解析,再做数据库操作。 EF 足够聪明,可以在您不更改配置时设置导航属性,这不再是必需的,因为 AddRange() 应该比 Add() 快得多,因为它只调用 detectchanges 一次。通过仅设置主管 ID,
我正在使用 Entity Framework 版本 6,需要在很短的时间内将数千个对象批量插入数据库。
因此我将 DbContext.Configuration.AutoDetectChangesEnabled
更改为 false 并且仅在添加了许多项后才使用 SaveChanges
。
这个实体,我们称它为 Person
,有一个导航 属性 到它自己,例如。 G。 Supervisor
.
现在我想将一个人添加到数据库中,并想用迭代前刚刚添加到上下文(只是本地,不在数据库中)的主管填充导航 属性。
由于性能原因,我只是在 200 万人之后调用 SaveChanges()。如果我在 SaveChanges
之后查看数据库,列 Supervisor
始终为 NULL。如何添加导航属性?
奇怪的是,我的实体模型有四个导航属性,分别名为 Supervisor1
、Supervisor2
、Supervisor11
和 Supervisor3
。为什么实体模型为一个数据库约束创建四个导航属性?
详细解释我的问题:这是我的 database structure. EntityFramework creates this model.
有一个循环来处理来自 csv 文件的数据:
db.DbContext.Configuration.AutoDetectChangesEnabled = false; // for performance
///...
while (!parser.EndOfData)
{
// process data from a csv file with a name and a supervisorId
db.AddNewPerson(name, supervisorId);
}
db.SaveChanges();
db.DbContext.Configuration.AutoDetectChangesEnabled = true;
这是数据访问层方法:
public void AddNewPerson(string name, long? supervisorId)
{
var dbSetPerson = dbContext.Set<Person>();
var newPerson = new Person(name);
dbSetPerson.Add(newPerson);
if (supervisorId != null)
{
var supervisor = dbSetPerson.Local.FirstOrDefault(x => x.PersonId == supervisorId); // first look if the supervisor was just processed in this loop
if (supervisor == null)
supervisor = dbSetPerson.FirstOrDefault(x => x.PersonId == supervisorId); // if the was no person found look in the database
if (supervisor != null)
newPerson.Person2 = supervisor;
}
}
提前感谢您的帮助!
我认为你的问题是,实体在这个阶段没有存储到数据库中,EF(代理)不知道它。您可以做的是在调用 StoreChanges():
之后附加它yourContext.Persons.Attach(justAddedPerson);
但是当你添加一些代码时,我可以给出更具体的答案。
更新 根据您的编辑(我猜 ID 是整数而不是自动创建的)我建议如下:
var persons = new List<Person>();
while (!parser.EndOfData)
{
var person = new Person { Name = parser... }
person.SupervisorId = parser...
list.Add(person);
}
dbSet.AddRange(persons);
dbContext.SaveChanges();
先做解析,再做数据库操作。 EF 足够聪明,可以在您不更改配置时设置导航属性,这不再是必需的,因为 AddRange() 应该比 Add() 快得多,因为它只调用 detectchanges 一次。通过仅设置主管 ID,