首页 新闻 会员 周边

请教efcore 3.1内嵌对象(值对象)不能更新问题

0
悬赏园豆:200 [已解决问题] 解决于 2021-03-02 18:19

问题是这样的,比方说我有一个Warehouse类,它有3个属性,3个属性中的Position属性是一个Class。两个class我映射到一张表中。

Warehouse与Position的代码如下

    public class Warehouse
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public WarehousePosition Position { get; set }
    }

    public class WarehousePosition
    {
        public string Code { get; set; }

        public string Description { get; set }
    }

映射Position代码如下,映射是没有问题的,可以正常生成。

 builder.OwnsOne(x => x.Position, y =>
{
       y.Property(x => x.Code).IsRequired().HasColumnName("PositionCode").HasMaxLength(32);
         y.Property(x => x.Description).HasColumnName("PositionDescription").HasMaxLength(64);
});

可以正常insert

如果修改了Name属性,可以正常更新

如果同时修改了Name属性与Position属性可以正常更新

如果只修改Position属性,就更新不了。跟踪实体的状态是unchange状态,伪代码如下。

var warehouse = await repo.FindAsync(1);
warehouse.Position = new WarehousePosition();
await dbContext.SaveChangesAsync(cancellationToken);
问题补充:

我在github,efcore的issues看了下,有很多人提出这个问题,但官方说3.0已经解决了。然而我用的3.1依旧不行。。头大。。

风口旁的猪的主页 风口旁的猪 | 菜鸟二级 | 园豆:211
提问于:2021-03-02 17:07

那试试 5.0 吧

dudu 3年前

@dudu: pomelo 5.0的版本还是alpha版本,再等等。

风口旁的猪 3年前
< >
分享
最佳答案
0

我猜测是 new WarehousePosition() 没有进入 EF Core 的跟踪范围

收获园豆:200
dudu | 高人七级 |园豆:31003 | 2021-03-02 17:12

var warehouse = await repo.FindAsync(1);
warehouse.Name="xxx";
warehouse.Position = new WarehousePosition();
await dbContext.SaveChangesAsync(cancellationToken);

如果这样就可以更新。Position,Name都会更新。

风口旁的猪 | 园豆:211 (菜鸟二级) | 2021-03-02 17:14

@风口旁的猪: 试试给 warehouse.Position.Code 赋值

dudu | 园豆:31003 (高人七级) | 2021-03-02 17:24

@dudu:
warehouse.Position.Code="xxxx";
await dbContext.SaveChangesAsync(cancellationToken)

这样依旧是unchange状态,更新不了。

风口旁的猪 | 园豆:211 (菜鸟二级) | 2021-03-02 17:57

@风口旁的猪: 更新之前 warehouse.Position 的值是什么?

dudu | 园豆:31003 (高人七级) | 2021-03-02 18:03

@风口旁的猪: 建议试试

var position = new WarehousePosition();
dbContext.Add(position);
warehouse.Position = position;
dudu | 园豆:31003 (高人七级) | 2021-03-02 18:06

@dudu: Position 更新之前,是有值的,可以从数据库正常读取出来,正常映射。

风口旁的猪 | 园豆:211 (菜鸟二级) | 2021-03-02 18:10

@dudu:
var position = new WarehousePosition();
warehouse.Position = position;
dbContext.Add(position);
await dbContext.SaveChangesAsync(cancellationToken)

这样成功了。谢谢。

风口旁的猪 | 园豆:211 (菜鸟二级) | 2021-03-02 18:18

因为我把efcore封装了一下,完整的解决方案如下代码。

        public virtual async Task<int> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default)
        {
            //获取实体状态
            var entry = DbContext.Entry(entity);

            //如果实体没有被跟踪,必须指定需要更新的列,这里是防止全字段更新
            if (entry.State == EntityState.Detached)
                throw new ArgumentException($"实体没有被跟踪,需要指定更新的列");

            //实体没有被更改
            if (entry.State == EntityState.Unchanged)
            {
	//找出导航属性并且是值对象,我的值对象都继承了ValueObject
                var navigations = entry.Navigations.Where(x => x.CurrentValue is ValueObject);
                if (navigations?.Count() > 0)
                {
                    foreach (var navigation in navigations)
                    {
	         //将值对象加入dbcontext
                        DbContext.Add(navigation.CurrentValue);
                    }
                }
                else
                    return await Task.FromResult(0);
            }

            return await DbContext.SaveChangesAsync(cancellationToken);
        }
风口旁的猪 | 园豆:211 (菜鸟二级) | 2021-03-02 18:36
其他回答(1)
0

我试了一下,你上面的例子是可以更新的,我用的core3.1。主要代码:
DbContext的OnModelCreating方法

Main方法调用:

没有星星的夏季 | 园豆:202 (菜鸟二级) | 2021-03-03 10:35
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册