代码优先实体框架不能更新许多相关实体

本文关键字:实体 更新 许多相 不能 框架 代码 | 更新日期: 2023-09-27 17:50:48

我在TicketsTags之间有多对多的关系,可以在没有问题的情况下向门票添加标签。但是,我无法更新/删除门票标签。

<标题> 测试
[TestMethod]
        public void TagRepository_UpdateTicketWithTwoTagsToNone_TicketHasZeroTag()
        {
            // Arrange
            var ticketId = new Guid("54E86203-71F9-E411-80E5-000C29193DF7");
            var selectedTags = "";
            using (var context = new TicketModelContext())
            {
                using (new TransactionScope())
                {
                    var ticketToUpdate = context.Tickets.Include(t=>t.Tags).First(t => t.TicketId == ticketId);
                    Assert.AreEqual(0, ticketToUpdate.Tags.Count);
                    ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("D1757675-A06C-4C1F-9DAD-03EE00BB1100")));
                    ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("96C66A97-9C3E-4B15-BD70-A4C832EEDE8B")));
                    context.SaveChanges();
                    var setupTicket = context.Tickets.Single(t => t.TicketId == ticketId);
                    Assert.AreEqual(2, setupTicket.Tags.Count);

                    // Act
                    new TagRepository().UpdateTicketTags(ticketId, selectedTags);
                    // Assert
                    var updatedTeicket = context.Tickets.Include(t => t.Tags).First(t => t.TicketId == ticketId);
                    Assert.AreEqual(0, updatedTeicket.Tags.Count);
                    // HERE I EXPECT 0 BUT GET 2
                }
            }
        }

库方法
public void UpdateTicketTags(Guid ticketId, string selectedTags)
        {
            var tags = new List<Tag>();
            using (var context = new TicketModelContext())
            {
                if (!String.IsNullOrEmpty(selectedTags))
                {
                    foreach (var selectedTag in selectedTags.Split(','))
                    {
                        tags.Add(context.Tags.Find(new Guid(selectedTag)));
                    }
                }
                var ticketToUpdateTags = context.Tickets.Find(ticketId);
                context.Entry(ticketToUpdateTags).Collection(t => t.Tags).Load();
                ticketToUpdateTags.Tags = tags; // I EXPECT TAGS TO BE EMPTY IN THIS TEST
                context.SaveChanges();
            }
        }

context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);命令输出的SQL

DELETE [dbo].[TagTickets]
WHERE (([Tag_TagId] = @0) AND ([Ticket_TicketId] = @1))

-- @0: '96c66a97-9c3e-4b15-bd70-a4c832eede8b' (Type = Guid)
-- @1: '54e86203-71f9-e411-80e5-000c29193df7' (Type = Guid)
-- Executing at 26/05/2015 13:16:39 +01:00
-- Completed in 24 ms with result: 1

DELETE [dbo].[TagTickets]
WHERE (([Tag_TagId] = @0) AND ([Ticket_TicketId] = @1))

-- @0: 'd1757675-a06c-4c1f-9dad-03ee00bb1100' (Type = Guid)
-- @1: '54e86203-71f9-e411-80e5-000c29193df7' (Type = Guid)
-- Executing at 26/05/2015 13:16:39 +01:00
-- Completed in 21 ms with result: 1

我花了几个小时用不同的测试尝试不同的代码变体,结果都是一样的。任何帮助将非常感激!

代码优先实体框架不能更新许多相关实体

基本上你的测试不工作的原因是因为在实体框架的不同上下文中发生的变化没有反映出来。即使您使用了TransactionScope,如果您在内部上下文中调用SaveChanges()(发生在UpdateTicketTags()中),那么这些更改将不会反映在外部上下文中。

我通常更喜欢将操作分解成更小的块,而不是一个长上下文,所以

  • 它模拟真实世界的动作如何在你的应用程序中发生(例如,如果这是一个ASP。. NET MVC应用程序,多个控制器正在处理多个请求,这些请求可能会或可能不会修改同一个表)和
  • 它给我每个对象的最新信息。

    [TestMethod]
    public void TagRepository_UpdateTicketWithTwoTagsToNone_TicketHasZeroTag()
    {
        // Arrange
        var ticketId = new Guid("54E86203-71F9-E411-80E5-000C29193DF7");
        var selectedTags = "";
        using (var context = new TicketModelContext())
        {
            var ticketToUpdate = context.Tickets.Include(t=>t.Tags).First(t => t.TicketId == ticketId);
            Assert.AreEqual(0, ticketToUpdate.Tags.Count);
            ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("D1757675-A06C-4C1F-9DAD-03EE00BB1100")));
            ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("96C66A97-9C3E-4B15-BD70-A4C832EEDE8B")));
            context.SaveChanges();
            var setupTicket = context.Tickets.Single(t => t.TicketId == ticketId);
            Assert.AreEqual(2, setupTicket.Tags.Count);
        }
        // Act
        new TagRepository().UpdateTicketTags(ticketId, selectedTags);
        using (var context = new TicketModelContext())
        {
            // Assert
            var updatedTeicket = context.Tickets.Include(t => t.Tags).First(t => t.TicketId == ticketId);
            Assert.AreEqual(0, updatedTeicket.Tags.Count);
        }
    }
    

嗯,我不确定你得到什么样的错误,但我猜你已经在web.config中设置了MultipleActiveResultSets为false。试着把它添加到网页上。config MultipleActiveResultSets=True到您的连接字符串。这将使EF能够在检索数据等时进行查询。从我的角度来看,你的代码看起来很好。

"多活动结果集(MARS)是一个与SQL Server一起工作的功能,允许在单个连接上执行多个批次。"https://msdn.microsoft.com/en-us/library/h32h3abf%28v=vs.110%29.aspx

我已经重新构建了我的测试代码,以在数据库上下文中删除存储库调用,并将我的事务范围移到外部以实现我所需要的。主要学习点是don't try and make changes to the database inside a context by calling another context

[TestMethod]
        public void TagRepository_UpdateTicketWithTwoTagsToNone_TicketHasZeroTag()
        {
            // Arrange
            var ticketId = new Guid("54E86203-71F9-E411-80E5-000C29193DF7");
            var selectedTags = "";
            using (new TransactionScope())
            {
                using (var context = new TicketModelContext())
                {
                    var ticketToUpdate = context.Tickets.Include(t => t.Tags).First(t => t.TicketId == ticketId);
                    Assert.AreEqual(0, ticketToUpdate.Tags.Count);
                    ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("D1757675-A06C-4C1F-9DAD-03EE00BB1100")));
                    ticketToUpdate.Tags.Add(context.Tags.Find(new Guid("96C66A97-9C3E-4B15-BD70-A4C832EEDE8B")));
                    context.SaveChanges();
                    var setupTicket = context.Tickets.Single(t => t.TicketId == ticketId);
                    Assert.AreEqual(2, setupTicket.Tags.Count);
                }
                // Act
                new TagRepository().UpdateTicketTags(ticketId, selectedTags);
                // Assert
                using (var context2 = new TicketModelContext())
                {
                    var updatedTeicket = context2.Tickets.Include(t => t.Tags).First(t => t.TicketId == ticketId);
                    Assert.AreEqual(0, updatedTeicket.Tags.Count);
                }
            }
        }