【问题标题】:Entity Framework SaveChanges() bug?实体框架 SaveChanges() 错误?
【发布时间】:2016-09-05 22:48:50
【问题描述】:

我有一个 CRUD 应用程序处理两个对象,卡片和日志。当用户创建、编辑或删除卡片时,会在数据库的 Log 表中创建一条新的 Log 记录。用户创建卡片时,Log记录的NewCard值为JSON数据,OldCard值为null。用户删除卡片时,Log记录的OldCard值为JSON数据,NewCard为空。

但是,每当我删除一张卡片时,Entity Framework 总是会创建这条用红圈圈起来的额外记录:

记录 2101 是 IActionResult CreateCreateNewLog(card, null) 之后的结果。记录 2102 和 2103 是在IActionResult DeleteCreateNewLog(null, oldCard) 之后的结果。记录 2103 是问题所在。如何阻止创建此记录?

CardController.cs

    private ICardData _cardData;
    private ILogData _logData;

    public CardController(ICardData cardData, ILogData logData)
    {
        _cardData = cardData;
        _logData = logData;
    }

    // POST api/card
    [HttpPost]
    public IActionResult Create([FromBody] Card card)
    {
        try
        {
            if (ModelState.IsValid)
            {
                _cardData.Add(card);
                CreateNewLog(card, null);

                Response.StatusCode = (int)HttpStatusCode.Created;
                return Json(new { Data = card });
            }
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(new { Message = ex.Message });
        }

        return Json("Failed");
    }

    // DELETE api/card/1
    [HttpDelete("{id}")]
    public void Delete(int id)
    {
        Card oldCard = _cardData.Get(id).ShallowCopy();
        CreateNewLog(null, oldCard);

        _cardData.Delete(id);
    }

    public void CreateNewLog(Card newCard, Card oldCard)
    {
        Log newLog = new Log()
        {
            DateChanged = DateTime.Now,

            CardId = newCard == null ? oldCard.CardId : newCard.CardId,
            OldCard = JsonConvert.SerializeObject(oldCard),
            NewCard = JsonConvert.SerializeObject(newCard),
            User = "John Smith"
        };

        _logData.Add(newLog);
    }

LogData.cs

public class SqlLogData : ILogData
{
    private LitmusDbContext _context;

    public SqlLogData(LitmusDbContext context)
    {
        _context = context;
    }

    public IEnumerable<Log> GetAll()
    {
        return _context.Logs.ToList();
    }

    public Log Get(int id)
    {
        return _context.Logs.FirstOrDefault(c => c.Id == id);
    }

    public void Add(Log newLog)
    {
        _context.Add(newLog);
        _context.SaveChanges();
    }

}

CardData.cs

public class SqlCardData : ICardData
    {
        private LitmusDbContext _context;

        public SqlCardData(LitmusDbContext context)
        {
            _context = context;
        }

        public IEnumerable<Card> GetAll()
        {
            return _context.Cards.ToList();
        }

        public Card Get(int id)
        {
            Card card = _context.Cards.FirstOrDefault(c => c.Id == id);

            return card;
        }

        public void Add(Card newCard)
        {
            _context.Add(newCard);
            _context.SaveChanges();
        }

        public int Commit()
        {
            _context.SaveChanges();
            return 0;
        }

        public void Update(Card newCard)
        {
            var oldCard = Get(newCard.Id);

            if (oldCard != null)
            {
                oldCard.CardId = newCard.CardId;
                oldCard.State = newCard.State;
                _context.SaveChanges();
            }
        }

        public void Delete(int id)
        {
            var cardToDelete = Get(id);

            _context.Remove(cardToDelete);
            _context.SaveChanges();
        }
    }

【问题讨论】:

  • 很高兴看到 _cardData.Delete(id); 的代码如果这个有问题......
  • 您可以从 web 和 sql profiler 中调试这些方法,以查看哪个方法调用了两次或发生在哪里
  • 您是否正在记录 SQL 输出?它可能会让你知道为什么会这样。 stackoverflow.com/questions/16880687/…
  • 是否有任何 SQL 触发器在幕后为您执行此操作?
  • 显示这个对象_cardData的类的代码。 _context 是否出于某种原因是静态的?

标签: c# asp.net entity-framework entity-framework-6 entity-framework-core


【解决方案1】:

根据提供的代码,我看不出这是怎么可能的。在任何时候都不会将新旧卡都提供给 CreateNewLog 函数,但是有些东西正在将序列化的卡保存到旧/新列中。

能否在 CreateNewLog 函数中下断点,找出两个参数的提供时间,然后查看调用堆栈?

【讨论】:

  • 哎呀。你说得对。刚刚意识到每次我执行删除操作时,我都会从我的前端代码中调用“更新”方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-19
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多