Entity Framework Core的TrackGraph用于无连接的数据,Entity Framework Core是Entity Framework的新轻量级版本,旨在与.NET Core应用程序一起使用。就像ASP.NET Core一样,它已经从头开始重写,并包含一些新的工作方式。其中之一是引入了TrackGraph(跟踪图,遍历跟跟对象)方法,用于处理无连接的场景(如MVC或Web API应用程序)中的复杂数据。
Entity Framework Core的TrackGraph用于无连接的数据
Entity Framework 能够基于其对任何给定实体图的当前状态的理解来生成要执行的正确SQL。 它知道这一点,因为它的ChangeTracker组件跟踪实体发生的事情。 如下例子:
using (var context = new TestContext())
{
var author = context.Authors.Single(a => a.AuthorId == 1);
author.FirstName = "Bill";
context.SaveChanges();
}
上下文检索到author
实体时,立即开始跟踪它。SaveChanges
调用该方法时,EF将检测对其正在跟踪的实体所做的任何更改并相应地生成SQL。在此示例中,仅FirstName
更改了属性:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE[Authors] SET[FirstName] = @p0
WHERE[AuthorId] = @p1;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000)',@p1=1,@p0=N'Bill'
如果要使用不是来自于当前上下文跟踪的实体对象,情况就比较麻烦。这些对象可能来自于MVC的方法,他们是通过Model绑定从表单值构建来的,也可能是在Web API方法中从JSON反序列化。如果您希望上下文处理保存任何更改,则需要将实体引入上下文,并且需要通知上下文所需的操作。
Entity Framework Core 保留了以前版本的方法DbContext
Add
和Attach
方法。它还包括一个新Update
方法,这些方法适用于单个实体,或者您不介意UPDATE
声明中包含的所有属性是否已更改。Entity Framework Core还引入了一个名为的新方法TrackGraph
,它能够跟踪嵌套对象,即一个根对象里面包含子对象,子对象又包含其它对象(即根实体和所有相关实体,以及与相关实体相关的所有实体,等等,递归)。
下面代码是应用TrackGraph(跟踪图),代码较简单,但意思表达到位。
var author = new Author
{
AuthorId = 1,
FirstName = "William",
LastName = "Shakespeare"
};
author.Books.Add(new Book { AuthorId = 1, BookId = 1, Title = "Hamlet", Isbn = "1234" });
author.Books.Add(new Book { AuthorId = 1, BookId = 2, Title = "Othello", Isbn = "4321" });
author.Books.Add(new Book { AuthorId = 1, BookId = 3, Title = "MacBeth", Isbn = "5678" });
让我们假设唯一被改变的是分配给每本书的ISBN号,并且该对象图被呈现给Save
存储库或服务层中的某个方法。该Save
方法使用了新DbContext.Update
方法:
public void Save(Author author)
{
using(var context = new TestContext())
{
context.Update(author);
context.SaveChanges();
}
}
该Update
方法将导致根实体和所有相关实体被跟踪为Modified
,并且将生成SQL以将其所有属性更新为已分配给实体的值,无论它们是否已被更改。这意味着必须存在所有实体的所有值,否则它们将被覆盖null
或默认值。
该TrackGraph
方法提供了更细粒度的控制,因为它提供了对图中每个实体的轻松访问。以下是该Save
方法的外观:
public void Save(Author author)
{
using (var context = new TestContext())
{
context.ChangeTracker.TrackGraph(author, e =>
{
e.Entry.State = EntityState.Unchanged;
if ((e.Entry.Entity as Book) != null)
{
context.Entry(e.Entry.Entity as Book).Property("Isbn").IsModified = true;
}
});
context.SaveChanges();
}
}
该TrackGraph
方法有两个参数:要从中开始跟踪的根实体,以及要对递归发现的每个实体执行的回调委托。在此示例中,回调首先将EntityState
值应用于每个实体,以便可以跟踪它。这对于后代发现很重要。如果未为实体分配EntityState
值,则不会跟踪该实体,也不会发现其后代。的UnChanged
状态下施加,这将导致在所采取的上下文中没有作用。但是,如果实体是Book
类型,则其Isbn
属性将标记为已修改,这将导致EntityState
该实体更改为Modified
。然后,就像在本文开头的示例中一样,生成的SQL只会更新Isbn
属性:
exec sp_executesql N'SET NOCOUNT ON;
UPDATE[Books] SET[Isbn] = @p0
WHERE[BookId] = @p1;
SELECT @@ROWCOUNT;
UPDATE[Books] SET[Isbn] = @p2
WHERE[BookId] = @p3;
SELECT @@ROWCOUNT;
UPDATE[Books] SET[Isbn] = @p4
WHERE[BookId] = @p5;
SELECT @@ROWCOUNT;
',N'@p1 int,@p0 nvarchar(4000),@p3 int,@p2 nvarchar(4000),@p5 int,@p4 nvarchar(4000)',
@p1=1,@p0=N'1234',
@p3=2,@p2=N'4321',
@p5=3,@p4=N'5678'
由于可以指定修改哪些属性,因此其它属性不用赋值(当然,除主键值除外)。
传递给TrackGraph
方法的委托的主体可以很容易地作为一个单独的方法来考虑,以达到代码重用目的:
void UpdateIsbn(EntityEntryGraphNode node,TestContext context)
{
node.Entry.State = EntityState .Unchanged;
if ((node.Entry.Entity as Book )!= null )
{
context.Entry(node.Entry.Entity as Book ).Property (“Isbn” )。IsModified = true ;
}
}
然后它可以像这样调用:
public void Save(Author author)
{
using (var context = new TestContext())
{
context.ChangeTracker.TrackGraph(author, e => UpdateIsbn(e, context));
context.SaveChanges();
}
}
最后
TrackGraph
方法是Entity Framework Core中的新方法,它提供了一种简单的方法来迭代您希望上下文开始跟踪的对象图,并根据实体类型和其他条件应用自定义代码。