You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 7替换Json存储的自有实体报错,该行为是否正常?

问题背景

我正在使用EF Core 7,通过以下配置将集合以JSON格式存储为实体表列:

builder.Entity<ShoppingChannels>().OwnsMany(s => s.ChannelProducts, options =>
{
    options.ToJson();
});

实体类定义如下:

public class ShoppingChannels
{
    [Key]
    public string Id { get; set; } 
    public List<ChannelProducts> ChannelProducts { get; set; } 
}

public class ChannelProducts
{
    public string ProductId { get; set; }
    public string Title { get; set; } = string.Empty;
    public double Price { get; set; }
}

我尝试通过替换集合的方式限制JSON元素数量为50:

using (var context = new DbContext())
{
    var shoppingChannelsList = await context.ShoppingChannels
                                            .ToListAsync();

    foreach (var channel in shoppingChannelsList)
    {
        var filteredChannelProducts = channel.ChannelProducts                        
                    .Take(50)
                    .ToList();

        channel.ChannelProducts = filteredChannelProducts;
    }

    await context.SaveChangesAsync();
}

执行SaveChanges时抛出异常:

System.InvalidOperationException: 'The instance of entity type 'ChannelProducts' cannot be tracked because another instance with the key value '{ShoppingChannelsId: fc470701-f01a-4f6b-b424-379edb315ada, Id: 1}' is already being tracked. When replacing owned entities, modify the properties without changing the instance or detach the previous owned entity entry first.'

改为逐个删除超出50的元素后代码可正常运行:

using (var context = new DbContext())
{
    var shoppingChannelsList = await context.ShoppingChannels
                                            .ToListAsync();

    foreach (var channel in shoppingChannelsList)
    {
        var productsToRemove = channel.ChannelProducts
                    .Skip(50)
                    .ToList();

        foreach (var product in productsToRemove)
        {
            channel.ChannelProducts.Remove(product);
        }
    }

    await context.SaveChangesAsync();
}

请问这是EF Core 7的正常行为,还是我在此场景中遗漏了某些逻辑?


解答

这是EF Core 7的正常行为,核心原因是EF Core对ToJson()存储的Owned集合的跟踪机制限制:

  • Owned实体的跟踪逻辑:加载ShoppingChannels时,EF Core会自动跟踪所有关联的ChannelProducts实例,每个Owned实体都带有隐式复合键(包含主实体ID和自身标识),这些实例会被上下文的变更追踪器记录。
  • 直接替换集合的冲突:当你直接赋值新集合channel.ChannelProducts = filteredChannelProducts时,原集合中被跟踪的ChannelProducts实例并未被上下文解除跟踪。新集合中的实例和原跟踪实例的复合键完全一致,导致变更追踪器触发"重复跟踪"的异常。
  • 逐个删除的正确性:通过Remove方法修改原集合时,EF Core会准确识别出被移除的元素,更新变更追踪器的状态,最终将这些变更转换为JSON列的更新操作,不会产生跟踪冲突。

总结:对于EF Core的Owned集合(尤其是JSON存储的类型),必须通过修改现有集合的内容(添加/删除元素)来变更数据,而非直接替换集合引用。

内容的提问来源于stack exchange,提问作者bob mason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:37:27