我有一个Task表(称为Task_Task)和一个Field表(称为Core_Field)。我还有Task_Field表,它将两者关联起来:
CREATE TABLE [dbo].[Task_Field](
[TaskId] [uniqueidentifier] NOT NULL,
[FieldId] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_Task_Field] PRIMARY KEY NONCLUSTERED
(
[TaskId] ASC,
[FieldId] ASC
))
我需要在此表中插入一些记录。我是这样做的:
dbTask.Core_Field.Clear();
List<Core_Field> dbFields = _context.Core_Field
.Where(x => fields.Contains(x.FieldId)).ToList();
foreach (var field in dbFields)
{
dbTask.Core_Field.Add(field);
}
这导致以下追踪:
在这种情况下,我们在List<Guid> fields
中有5个guid。我们看到这个疯狂值(这是查询运行的时间)的原因是因为Core_Field表中的行非常宽。他们有一些包含大量数据的二进制字段。如果我不检索这些字段,而是做这样的事情:
var tmp = _context.Core_Field
.Where(x =>fields.Contains(x.FieldId))
.Select(x => x.SomeField).ToList();
时间从~1000ms下降到几ms,大多数情况下为零。
正如您所见,插入记录也不会花费很长时间。
现在,我不需要该表中的整行。哎呀,我不需要那个表中的任何,我已经有了所有要插入的guid。
这就是EF关系的样子:
我想知道,如何有效地将这些记录添加到链接表中。当然,我总是可以运行ExecuteSqlCommand方法,并且在不使用任务或字段实体的情况下进行更新,但我想知道是否有更多EF - 惯用的方法。
答案 0 :(得分:3)
在这行代码中......
dbTask.Core_Field.Add(field)
...由于延迟加载,dbTask.Core_Field
已加载。
如果禁用延迟加载,您将看到主要的性能提升:
_context.Configuration.LazyLoadingEnabled = false;
但是,既然你已经拥有了要插入的所有guid&#34;,那么使用存根实体可以获得更多(尽管更少),只有Id的实体值。毕竟,EF只需要Id值来创建关联:
List<Core_Field> dbFields = fields.Select(f => new Core_Field { FieldId = f }).ToList();
foreach (var field in dbFields)
{
_context.Core_Fields.Attach(field);
dbTask.Core_Field.Add(field);
}
一个警告:由于禁用了延迟加载,EF不再跟踪dbTask.Core_Field
。这意味着它不再发现重复。使用延迟加载,EF将忽略重复的联结记录。如果没有它,如果您尝试插入重复项,则会出现重复的键错误。所以你可能想事先检查一下:
fields = _context.Code_Tasks
.Where(t => t.TaskId == id)
.SelectMany(t => t.Core_Field)
.Where(c => !fields.Contains(c.FieldId))
.Select(c => c.FieldId).ToList();
这是一个相对轻量级的查询。