如何更新Entity Framework中的唯一键

时间:2017-12-14 16:23:17

标签: c# entity-framework

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的另一种方法是将每天的所有其他数据传输到下一个数据,但这似乎效率低下,在某些情况下可能是不合需要的,因为这意味着数据与数据分离Day的主要关键值。

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

2 个答案:

答案 0 :(得分: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
} 

答案 1 :(得分:0)

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

你可以先把时间存放在内存中。

var days = db.Day.Tolist();

截断表格,以便他们不会碰到新列表:

db.ExecuteCommand("TRUNCATE TABLE Day");

做你的东西:

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

插入新列表。 现在你应该能够保存它:

db.SaveChanges();

这应该足够有效,因为擦除数据的最快方法是截断,并且你的日期对象是子对象。

<强>无论其

如果一个房产发生了很大的变化,那么把它作为主要钥匙可能并不是一个好主意。

如果您发现自己与基本面发生冲突,很可能会造成架构错误。

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