【问题标题】:How to update unique keys in Entity Framework如何更新实体框架中的唯一键
【发布时间】:2017-12-15 04:44:10
【问题描述】:

previous question 中,我展示了这些模型:

public class Calendar 
{
    public int ID { get; set; }
    public ICollection<Day> Days { get; set; }
}

public class Day
{
    public int ID { get; set; }
    public DateTime Date { get; set; }
    public int CalendarID { get; set; }
}

存在唯一性约束,因此您不能有多个 Day 具有相同的 DateCalendarID

我现在的问题是,如果我想把所有的日子都转移到未来的某一天(或其他什么)。最简单的代码就是一个类似的for循环

for(Day day in days) {
    day.Date = day.Date.AddDays(1);
    db.Entry(day).State = EntityState.Modified;
}
await db.SaveChangesAsync();

但是,这将失败,因为它认为您正在创建某些日期的重复项,即使它们全部更新后它也会解决。

每天之后调用SaveChangesAsync(假设您以正确的顺序处理这些日子)​​会起作用,但对于这项基本任务来说似乎效率非常低。

更新Date 的替代方法是将每天的所有其他数据转移到下一天,但这似乎也效率低下,并且在某些情况下可能是不可取的,因为这意味着数据与当天的主要数据分离键值。

有没有办法在保持唯一性约束的同时更新所有日期?

【问题讨论】:

  • 你可以反向更新它们,这样你就可以在它们之间创建一个间隙,而不是覆盖序列中的下一个并违反约束?
  • 将第 01 天设置为 lastDay + 1,结果相同,更新 1 次,最快模式。
  • 我尝试以相反的顺序更新它们。没有区别,除非你在每个循环中调用SaveChangesAsync
  • @CelsoLívero 这些模型只是说明性的。在现实世界中,这些天还有其他属性,因此将第 1 天设为最后一天是行不通的。需要保持顺序,就在一天之内将它们全部移动。
  • 我知道,这只是个玩笑,我知道不是很好。在这种情况下(和性能方面)最好的做法是在数据库中创建一个存储过程来执行所有需要的操作,所有与该更改相关的必要功能,并使 EF 执行此过程,即将为可能已扩展以执行此类工作的服务器转移所有工作

标签: c# entity-framework


【解决方案1】:

如果您为每条记录调用 SaveChanges() 而不是只调用一次,SQL UPDATE 语句的数量不会改变,但至少您会得到正确的顺序。由于状态清理和连接管理存在一些开销,但它并不是非常低效。

如果日期转换是一个孤立的业务事务,您可以使用更简单的解决方案而不是使用 ORM - 调用存储过程或直接执行 SQL,类似于:

var sql = "UPDATE d SET Date = DATEADD(d, 1, Date) FROM (SELECT * FROM Day WHERE CalendarID=@calendarId ORDER BY Date DESC) d";
var updateCnt = db.Database.ExecuteSqlCommand(sql, new SqlParameter("@calendarId", calendar.Id);
if (updateCnt != days.Count)
{
    //oops
} 

【讨论】:

    【解决方案2】:

    许多可能的解决方案之一是在更新之前删除所有记录。

    你可以先得到你的日子,把它们储存在记忆里。

    var days = db.Day.Tolist();
    

    截断表格,这样它们就不会与即将到来的新列表发生冲突:

    db.ExecuteCommand("TRUNCATE TABLE Day");
    

    做你的事:

    foreach(var day in days)
    {
        day.Date=day.Date.AddDays(1);
    }
    

    插入您的新列表。 现在你应该可以保存它了:

    db.SaveChanges();
    

    这应该足够有效,因为擦除数据的最快方法是截断,而您的 day 对象是子对象。

    但是

    如果一个属性发生了很大变化,那么将其设为主键可能不是一个好主意。

    如果您发现自己与基本原理发生冲突,那么您很可能犯了架构错误。

    我强烈建议您将主键更改为其他内容,您甚至可以滚动一个 uniqueidentifier 列来存储 Id。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-22
      • 1970-01-01
      • 1970-01-01
      • 2015-12-20
      • 1970-01-01
      相关资源
      最近更新 更多