在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
Date
和CalendarID
。
我现在的问题是如果我想把所有日子都搬到未来(或其他什么)。最简单的代码只是像
这样的for循环for(Day day in days) {
day.Date = day.Date.AddDays(1);
db.Entry(day).State = EntityState.Modified;
}
await db.SaveChangesAsync();
然而,这将失败,因为它认为您正在创建某些日期的副本,即使它们全部更新后也会有效。
每天之后调用SaveChangesAsync
(假设您按照正确的顺序处理日期)会起作用,但对于这个基本任务来说似乎效率很低。
更新Date
的另一种方法是将每天的所有其他数据传输到下一个数据,但这似乎效率低下,在某些情况下可能是不合需要的,因为这意味着数据与数据分离Day的主要关键值。
有没有办法在保持唯一性约束的同时更新所有日期?
答案 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。