繁体   English   中英

尽管 State=Modified,为什么 EF Core 只生成父(游戏)属性更新?

[英]Why EF Core generates only parent(Game) properties updating despite State=Modified?

var game = _context.Games
            .AsNoTracking()
            .Where(x => x.Id == 1)
            .Include(x => x.PlatformTypes)
            .Include(x => x.Genres)
            .Include(x => x.Publisher)
            .First();
        
game.Description = "New Description";
_context.Attach(game).State = EntityState.Modified;
_context.SaveChanges();

// CONVERTS TO

SET NOCOUNT ON;
UPDATE [Games] SET [Description] = @p0, [Discontinued] = @p1, [Key] = 
@p2, [Name] = @p3, [Price] = @p4, [PublisherId] = @p5, [UnitsInStock] = 
@p6
WHERE [Id] = @p7;
SELECT @@ROWCOUNT;
  1. 获得带有嵌套实体的实体游戏 - 状态 = 分离,无跟踪
  2. 更新的游戏描述 - 状态 = 分离,无跟踪
  3. 将游戏附加到上下文 - 状态 = 游戏内所有内容均未更改,跟踪已开始
  4. 将状态设置为已修改 - 状态 = 已修改游戏内的所有内容

SaveChanges 时,EF Core 仅生成游戏的属性(不包括嵌套实体)更新查询。 尽管 Entry 中的所有嵌套实体都具有 IsModified = true,为什么它不生成嵌套实体的更新?

在已发布中修改为 true

EntityEntry对象上的State属性(由Attach()方法返回)仅更改该特定对象的状态,而不更改可通过导航属性访问的整个对象树的状态。 检查该属性的文档:

此方法仅设置此条目表示的单个实体的状态。 它不会改变从这个实体可达的其他实体的状态。

因此,您的game实例被标记为“已修改”,但其他导航属性(如Publisher )则没有。

代码失败是因为AsNoTracking()告诉 EF不要跟踪对象的任何更改。 这意味着 EF 不知道Description已更改。 其余的基于错误的假设,即所有相关实体都将被标记为已Modified

game被保存只是因为它已附加并明确标记为已修改。 _context.Attach(game)告诉 EF 开始跟踪任意(分离的)对象game和任何可到达的实体作为Unchanged 据 EF 所知,此对象可能来自 POST 调用或 JSON 文件。 DbContext.Attach文档:

默认情况下,使用 Unchanged 状态开始跟踪给定实体和从给定实体可达的条目。

该方法仅返回game实体的 EntityEntry

返回实体的 EntityEntry。 该条目提供对实体的更改跟踪信息和操作的访问。

Attach文档页面明确指出Use State to set the state of only a single entity.

此时, game实体保持不变。 然后代码告诉 EF game被修改了。 线

_context.Attach(game).State = EntityState.Modified;

相当于:

var gameEntry=_context.Attach(game);
gameEntry.State = EntityState.Modified;

EntityEntry仅跟踪单个实体:

提供对给定实体的更改跟踪信息和操作的访问。

它的State 属性文档明确指出:

此方法仅设置此条目表示的单个实体的状态。 它不会改变从这个实体可达的其他实体的状态。

此时EF只知道它有一个Modified实体,它不知道修改了什么。 由于使用了AsNoTracking ,因此没有可比较的先前状态。 EF必须保存对象的所有属性。

但是,没有任何相关实体被修改,因此 EF 不必更新或插入它们。 即使它们在Attach之前被修改,EF 也不会知道,因为它们都没有被标记为Modified EF 只能跟踪在Attach之后所做的修改。

要解决此问题,请删除AsNoTracking()

var game = _context.Games
            .Where(x => x.Id == 1)
            .Include(x => x.PlatformTypes)
            .Include(x => x.Genres)
            .Include(x => x.Publisher)
            .First();
        
game.Description = "New Description";

_context.SaveChanges();

关于截图

屏幕截图没有显示Publisher等相关实体的EntityEntry ,它显示了game成员的内部更改跟踪表。 要查找Publisher的状态,您必须使用DbContext.Entry提取条目并检查其状态:

var publisherEntry=_context.Entry(game.Publisher);
Console.WriteLine(publisherEntry.State);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM