我遇到一个问题,实体框架(核心)在更新时删除对象。我认为这与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);
}
我不知道要在这里解决什么问题,也无法在任何谷歌搜索中看到这个问题。
我面临着类似的情况(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
应该始终具有价值。
这有点旧,但我在 EF Core 2.2 中遇到了同样的问题,并基于此 EntityFrameworkCore 3.0 中仍然存在问题
问题似乎是导航属性为空导致实体被删除。
我能够通过配置延迟加载来解决
安装此软件包
Microsoft.EntityFrameworkCore.Proxies
在配置中启用延迟加载
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies();
对我来说,如果我将实体标记为“分离”,使用自动映射器进行映射,然后将实体标记为“已修改”,则可以解决此问题。
_context.Entry(product).State = EntityState.Detached;
_mapper.Map<ProductVM, Product>(viewModelProduct, product);
_context.Entry(product).State = EntityState.Modified;
_context.SaveChanges();
嗯,我在我公司代码的用例中使用此方法遇到了同样的问题:
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(我发现它是最糟糕的方式,哈哈)
实体框架需要知道是否要更新或删除。您需要通过在
SaveChanges()
: 之前给出 EntityState 来解决此问题
dbContext.Entry(yourUpdatingEntity).State = EntityState.Modified;
dbcontect.SaveChages();