插入到链接表而不先获取

时间:2015-07-27 12:29:55

标签: c# sql-server entity-framework

我有一个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);
}

这导致以下追踪:

enter image description here

在这种情况下,我们在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关系的样子:

enter image description here

我想知道,如何有效地将这些记录添加到链接表中。当然,我总是可以运行ExecuteSqlCommand方法,并且在不使用任务或字段实体的情况下进行更新,但我想知道是否有更多EF - 惯用的方法。

1 个答案:

答案 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();

这是一个相对轻量级的查询。