实体框架在更新时删除对象

问题描述 投票:0回答:5

我遇到一个问题,实体框架(核心)在更新时删除对象。我认为这与Automapper(将DTO资源映射到对象)有关。我有其他对象以与该对象完全相同的方式映射,并且更新工作得很好。

public async Task<IActionResult> UpdateFeedback(Guid Id, [FromBody] FeedbackResource feedbackResource)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
    //removing or else get a tracking error with EF
    feedbackResource.FeedbackType = null;
    var feedback = await feedbackRepository.GetFeedback(Id);

    if (feedback == null)
        return NotFound();

    //if I use this line to map, EF will delete the object upon save.  

    mapper.Map<FeedbackResource, Feedback>(feedbackResource, feedback);

    // if I map manually, i get no error
    //feedback.Title = feedbackResource.Title;
    //feedback.Details = feedbackResource.Details;
    //feedback.IsGoodFeedback = feedbackResource.IsGoodFeedback;
    //feedback.IsReviewed = feedbackResource.IsReviewed;
    //feedback.FeedbackTypeId = feedbackResource.FeedbackTypeId;

    //if(feedbackResource.IsReviewed){
    //    feedback.ReviewDate = DateTime.Now;
    //    feedback.ReviewedBy = UserId;
    //} else {
    //    feedback.ReviewDate = null;
    //    feedback.ReviewedBy = null;
    //}

    await uow.CompleteAsync();

    return Accepted(feedback); 
}

我不知道要在这里解决什么问题,也无法在任何谷歌搜索中看到这个问题。

automapper entity-framework-core
5个回答
5
投票

我面临着类似的情况(ef core 1.1)。我假设你的问题与我的类似。

这里也描述了类似的问题

我有以下型号:

1) ApplicatonUser - 来自 EF 的标准用户

2)AnyDAL - 数据库中的任何类,链接到用户

 public class AnyDAL
 {
    public long Id { get; set; }

    public long UserId { get; set; }
    public ApplicationUser User { get; set; }
}

3)AnyDTO - 来自浏览器端的模型。喜欢你的

[FromBody] FeedbackResource feedbackResource

public class AnyDTO
{
    public long Id { get; set; }

    public long UserId { get; set; }

    /// It is root of all evil. See below.
    /// And yes, it is bad practice.
    public ApplicationUser User { get; set; }
}

场景:

1)从数据库中获取

AnyDAL

2) 使用 AutoMapper

AnyDTO
AnyDAL
映射到
_mapper.Map(DTO, DAL)

3)保存更改()

在一种情况下,

SaveChanges()
导致删除,在另一种情况下导致更新。

我们应该知道的是:在我的例子中,反序列化后,属性

AnyDTO.User
始终是
null

选择删除还是更新取决于映射前属性

AnyDAL.User
的值:

1)

AnyDAL.User
为空 - 我们得到更新。

2)

AnyDAL.User
不为空 - 我们得到删除。

换句话说。如果属性

AnyDAL.User
从某个值更改为 null - 实体将被删除。尽管事实上
AnyDAL.UserId
保持不变。

有两种方法可以解决:

1) 从

User
中删除属性
AnyDTO
;

2) 属性

AnyDTO.User
应该始终具有价值。


0
投票

这有点旧,但我在 EF Core 2.2 中遇到了同样的问题,并基于此 EntityFrameworkCore 3.0 中仍然存在问题

问题似乎是导航属性为空导致实体被删除。

我能够通过配置延迟加载来解决

安装此软件包

Microsoft.EntityFrameworkCore.Proxies

在配置中启用延迟加载

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseLazyLoadingProxies();

0
投票

对我来说,如果我将实体标记为“分离”,使用自动映射器进行映射,然后将实体标记为“已修改”,则可以解决此问题。

        _context.Entry(product).State = EntityState.Detached;

        _mapper.Map<ProductVM, Product>(viewModelProduct, product);

        _context.Entry(product).State = EntityState.Modified;

        _context.SaveChanges();

0
投票

嗯,我在我公司代码的用例中使用此方法遇到了同样的问题:

        private List<ElementoCronograma> UpdateAllCronogramaElementos(Cronograma cronograma, List<ElementoCronograma> elementosInputFlat)
        {
            List<ElementoCronograma> updatedElements = [];
            foreach (var elemento in cronograma.Elementos)
            {
                var currentInput = elementosInputFlat.Single(x => x.Id == elemento.Id);

                _mapper.Map(currentInput, elemento); // Here was the problem

                elemento.Filhos.Clear();

                updatedElements.Add(currentInput);
            }

            return updatedElements;
        }

刚刚发现,当将输入元素转换为我的数据库实体对象(ElementoCronograma)时,我没有设置 elementInput.Cronograma,仅设置属性 CronogramaId。无论出于何种原因,EF 都会出现错误并删除它,即使设置了 CronogramaId。

有错误的代码:

        private List<ElementoCronograma> ToElementosCronogramasWithPaiIdAndFilhos(
            EditarCronogramaInput input,
            Cronograma cronograma)
        {
            List<ElementoCronograma> elementosInputFlat = [
                .. _mapper.Map<List<Marco>>(input.Marcos),
                .. input.Marcos.SelectMany(x => x.Arvore.Filhos).Select(_mapper.Map<ElementoCronograma>)
            ];

            foreach (var elementInput in elementosInputFlat)
            {
                elementInput.CronogramaId = cronograma.Id;
                // elementInput.Cronograma = cronograma; // this line didnt exist
                var parent = elementosInputFlat.SingleOrDefault(x => x.Filhos.Any(x => x.Id == elementInput.Id));

                if (parent == null)
                {
                    if (elementInput.Tipo != Domain.Constants.Enums.iPlanner.TipoElemento.Marco)
                        throw new ArgumentException("Apenas marcos devem e podem ser raiz");

                    continue;
                }

                elementInput.PaiId = parent.Id;
            }

            SetOrdem(input, elementosInputFlat);

            return elementosInputFlat;
        }

其他观察结果

这是一个非常奇怪的行为,因为当我创建相关实体和更新时,我们有如此不同的行为

创建:甚至不需要在主实体集合中设置它,只需在创建的相关实体中引用它的id即可; (甚至不需要设置 relatedEntity.MainEntity,只需设置 .MainEntityId)并调用 db.Set().Add(latedEntity) (否则它将不起作用)

更新:不需要 dbSet.Update(relatedEntity),但需要更新 .MainEntityId 和 .MainEntity(我发现它是最糟糕的方式,哈哈)


-1
投票

实体框架需要知道是否要更新或删除。您需要通过在

SaveChanges()
:

之前给出 EntityState 来解决此问题
dbContext.Entry(yourUpdatingEntity).State = EntityState.Modified;
dbcontect.SaveChages();
© www.soinside.com 2019 - 2024. All rights reserved.