插入到链接表而不先获取

And*_*ykh 6 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
    ))
Run Code Online (Sandbox Code Playgroud)

我需要在这个表中插入一些记录.我是这样做的:

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);
}
Run Code Online (Sandbox Code Playgroud)

这导致以下跟踪:

在此输入图像描述

在这种情况下,我们有5个guid List<Guid> fields.我们看到这个疯狂值(这是查询运行的时间)的原因是因为Core_Field表中的行非常宽.他们有一些包含大量数据的二进制字段.如果我不检索这些字段,而是执行类似的操作:

var tmp = _context.Core_Field
    .Where(x =>fields.Contains(x.FieldId))
    .Select(x => x.SomeField).ToList();
Run Code Online (Sandbox Code Playgroud)

时间从~1000ms下降到几ms,大多数情况下为零.

正如您所看到的,插入记录也不会花费很长时间.

现在,我不需要该表中的整行.哎呀,我不需要那张桌子上的任何东西,我已经插入了所有的指南.

这就是EF关系的样子:

在此输入图像描述

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

Ger*_*old 3

在这行代码中...

dbTask.Core_Field.Add(field)
Run Code Online (Sandbox Code Playgroud)

...dbTask.Core_Field由于延迟加载而加载。

如果禁用延迟加载,您将看到显着的性能提升:

_context.Configuration.LazyLoadingEnabled = false;
Run Code Online (Sandbox Code Playgroud)

但是,由于您“已经拥有要插入的所有 guid”,因此您可以通过使用存根实体(仅具有 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);
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是:由于禁用了延迟加载,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();
Run Code Online (Sandbox Code Playgroud)

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