Entity Framework 在调用 INSERT 之前加载所有行
Entity Framework loads all rows before calling INSERT
我有一些我认为效率不高的 Entity Framework 代码。基本上,我有一个 ApplicationUser class 看起来像这样:
public class ApplicationUser : IdentityUser
{
public string CompanyName { get; set; }
public virtual ICollection<SolverRun> Runs { get; set; }
// .. other stuff generated by the Visual Studio template
}
我想做的是在 SolverRuns
中为当前用户创建一个新行:
// Log run in database
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentUser = manager.FindById(OwnerId);
currentUser.Runs.Add(new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime
});
manager.Update(currentUser);
效果很好。但是,我看到的是以下查询:
exec sp_executesql N'SELECT
[Extent1].[SolverRunID] AS [SolverRunID],
[Extent1].[RunName] AS [RunName],
[Extent1].[Base] AS [Base],
[Extent1].[Start] AS [Start],
[Extent1].[Duration] AS [Duration],
[Extent1].[Result] AS [Result],
[Extent1].[ApplicationUser_Id] AS [ApplicationUser_Id]
FROM [dbo].[SolverRuns] AS [Extent1]
WHERE ([Extent1].[ApplicationUser_Id] IS NOT NULL) AND ([Extent1].[ApplicationUser_Id] = @EntityKeyValue1)',N'@EntityKeyValue1 nvarchar(128)',@EntityKeyValue1=N'029a20a9-b487-4579-87d0-50608ed7f058'
这将为该用户select SolverRuns
table 中的每一行。我 怀疑 getter currentUser.Runs
.
我担心随着用户添加越来越多的 运行s(最终可能有数千个),这会变得越来越慢。有没有办法只 add 新行,而不是先 select 一切?谢谢!
更新:
根据下面 py3r3str 的回答,这是我的新工作代码(在更改模型和迁移数据库等之后):
// Log run in database
using (var dbContext = new ApplicationDbContext())
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(dbContext));
var currentUser = manager.FindById(job.OwnerId);
dbContext.Set<SolverRun>().Add(new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime,
ApplicationUser = currentUser
});
dbContext.SaveChanges();
}
它现在将 运行 这个 INSERT
语句(这很奇怪,但我放弃了尝试理解 EF SQL 查询所以我假设有人比我认为的更聪明高效):
exec sp_executesql N'INSERT [dbo].[SolverRuns]([ApplicationUserId], [RunName], [Base], [Start], [Duration], [Result])
VALUES (@0, @1, @2, @3, @4, @5)
SELECT [SolverRunID]
FROM [dbo].[SolverRuns]
WHERE @@ROWCOUNT > 0 AND [SolverRunID] = scope_identity()',N'@0 nvarchar(128),@1 nvarchar(max) ,@2 nvarchar(max) ,@3 datetime2(7),@4 time(7),@5 nvarchar(max) ',@0=N'029a20a9-b487-4579-87d0-50608ed7f058',@1=N'PilotRun',@2=N'YUL',@3='2015-09-03 11:07:32.0353181',@4='00:00:04.1521401',@5=N'Success'
请注意,调用 currentUser.Runs
将延迟加载所有 运行,如预期的那样。
最简单的方法之一是将外键添加到您的 SolverRun
实体:
class SolverRun
{
...
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
并且使用 ApplicationContext 仅保存 SolverRun
个实体:
var solverRun = new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime,
ApplicationUserId = OwnerId
};
dbContext.Set<SolverRun>().Add(solverRun);
dbContext.SaveChanges();
在那种情况下,EF 也会在 ApplicationUser.Runs
中添加对象。
我有一些我认为效率不高的 Entity Framework 代码。基本上,我有一个 ApplicationUser class 看起来像这样:
public class ApplicationUser : IdentityUser
{
public string CompanyName { get; set; }
public virtual ICollection<SolverRun> Runs { get; set; }
// .. other stuff generated by the Visual Studio template
}
我想做的是在 SolverRuns
中为当前用户创建一个新行:
// Log run in database
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentUser = manager.FindById(OwnerId);
currentUser.Runs.Add(new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime
});
manager.Update(currentUser);
效果很好。但是,我看到的是以下查询:
exec sp_executesql N'SELECT
[Extent1].[SolverRunID] AS [SolverRunID],
[Extent1].[RunName] AS [RunName],
[Extent1].[Base] AS [Base],
[Extent1].[Start] AS [Start],
[Extent1].[Duration] AS [Duration],
[Extent1].[Result] AS [Result],
[Extent1].[ApplicationUser_Id] AS [ApplicationUser_Id]
FROM [dbo].[SolverRuns] AS [Extent1]
WHERE ([Extent1].[ApplicationUser_Id] IS NOT NULL) AND ([Extent1].[ApplicationUser_Id] = @EntityKeyValue1)',N'@EntityKeyValue1 nvarchar(128)',@EntityKeyValue1=N'029a20a9-b487-4579-87d0-50608ed7f058'
这将为该用户select SolverRuns
table 中的每一行。我 怀疑 getter currentUser.Runs
.
我担心随着用户添加越来越多的 运行s(最终可能有数千个),这会变得越来越慢。有没有办法只 add 新行,而不是先 select 一切?谢谢!
更新:
根据下面 py3r3str 的回答,这是我的新工作代码(在更改模型和迁移数据库等之后):
// Log run in database
using (var dbContext = new ApplicationDbContext())
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(dbContext));
var currentUser = manager.FindById(job.OwnerId);
dbContext.Set<SolverRun>().Add(new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime,
ApplicationUser = currentUser
});
dbContext.SaveChanges();
}
它现在将 运行 这个 INSERT
语句(这很奇怪,但我放弃了尝试理解 EF SQL 查询所以我假设有人比我认为的更聪明高效):
exec sp_executesql N'INSERT [dbo].[SolverRuns]([ApplicationUserId], [RunName], [Base], [Start], [Duration], [Result])
VALUES (@0, @1, @2, @3, @4, @5)
SELECT [SolverRunID]
FROM [dbo].[SolverRuns]
WHERE @@ROWCOUNT > 0 AND [SolverRunID] = scope_identity()',N'@0 nvarchar(128),@1 nvarchar(max) ,@2 nvarchar(max) ,@3 datetime2(7),@4 time(7),@5 nvarchar(max) ',@0=N'029a20a9-b487-4579-87d0-50608ed7f058',@1=N'PilotRun',@2=N'YUL',@3='2015-09-03 11:07:32.0353181',@4='00:00:04.1521401',@5=N'Success'
请注意,调用 currentUser.Runs
将延迟加载所有 运行,如预期的那样。
最简单的方法之一是将外键添加到您的 SolverRun
实体:
class SolverRun
{
...
public string ApplicationUserId { get; set; }
[ForeignKey("ApplicationUserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
}
并且使用 ApplicationContext 仅保存 SolverRun
个实体:
var solverRun = new SolverRun
{
Base = job.Base,
Duration = context.JobRunTime,
Result = (context.Result ?? "").ToString(),
RunName = job.RunName,
Start = context.FireTimeUtc.GetValueOrDefault().LocalDateTime,
ApplicationUserId = OwnerId
};
dbContext.Set<SolverRun>().Add(solverRun);
dbContext.SaveChanges();
在那种情况下,EF 也会在 ApplicationUser.Runs
中添加对象。