c# - 代码优先 Entity Framework 无法更新多对多相关实体

标签 c# entity-framework

我在 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();
            }
        }

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

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

我花了数小时尝试使用不同测试的不同代码变体,结果都相同。任何帮助将不胜感激!

最佳答案

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

我通常更喜欢将 Action 分解成更小的 block 而不是一个长的上下文,这样

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

    [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);
        }
    }
    

关于c# - 代码优先 Entity Framework 无法更新多对多相关实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30456876/

相关文章:

c# - 如何在 NUnit 3.2 中创建全局初始化?

c# - UWP SolidColorBrush - 应用程序调用为不同线程异常编码的接口(interface)

c# - Azure WebJob不触发队列

c# - 处理@@Identity 时转换无效

c# - EF 5 一对多自引用 - 代码优先

entity-framework - 在 Entity Framework 中禁用外键暴露?

c# - 在 NHibernate 中全局查找对象引用

c# - 可怕又大的 LINQ 语句优化

c# - 如何在 EF 查询中使用函数参数化选择器?

c# - 使用 EF Core 将 SQL 转换为 Linq