这可能是一个简单的问题,但是我是Code First和Migrations的新手,因此需要我。我会继续示例代码到最低限度,借以说明问题:制作AddOrUpdate仅更改一些属性
我有一个BaseAuditableEntity
,其中包括本(除其他事项外,但让我们简化):
public abstract class BaseAuditableEntity : BaseEntity, IAuditableEntity
{
public DateTime CreatedOn { get; set; }
public DateTime LastModified { get; set; }
}
现在,(例如)User
POCO从它继承:
public class User : BaseAuditableEntity
{
public string UserName { get; set; }
public string PasswordHash { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
public bool Active { get; set; }
public DateTime? LastLogin { get; set; }
}
我有这个在我的上下文的SaveChanges
方法,填补了CreatedOn
和LastModified
日期(简体):
public override int SaveChanges()
{
var changeSet = ChangeTracker.Entries<IAuditableEntity>();
if (changeSet != null)
{
foreach (var entry in changeSet.Where(p => p.State != EntityState.Unchanged))
{
var now = DateTime.UtcNow;
if (entry.State == EntityState.Added)
entry.Entity.CreatedOn = now;
entry.Entity.LastModified = now;
}
}
return base.SaveChanges();
}
现在我有地方种子一些用户来说,这样的迁移:
protected override void Seed(MyContext context)
{
context.Users.AddOrUpdate(
p => p.UserName,
new User { Active = true,
FullName = "My user name",
UserName = "ThisUser",
PasswordHash = "",
Email = "[email protected]",
LastLogin = null,
}
// etc.
);
}
现在我有播种有问题,在迁移之后AddOrUpdate
。当实体是新的时候(它被添加),CreatedOn
被正确填充并且一切按预期工作。但是,当实体被修改时(它已经存在于数据库和UserName
匹配项中),它会尝试使用我正在创建的新实体更新它...因为CreatedOn
的DateTime
(本例中为DateTime.MinValue
)的值无效。
有什么方法可以使用AddOrUpdate
方法,以便它实际上从数据库中检索匹配的实体并更新非默认字段?或者,也许某种方式来告诉它哪些字段不更新?对于这种特定情况,我希望CreatedOn
字段保持不变,但一般的解决方案将不胜感激。
也许我应该做我自己的AddOrUpdate
方法,其中包括一个谓词与我想改变的领域,而不是传递一个全新的实体?
这是EF 6.1
更新
我知道我可以很容易地解决这个为CreatedOn
日期,这是目前我在做什么,这种特定的情况:
foreach (var entry in changeSet.Where(c => c.State != EntityState.Unchanged))
{
var now = DateTime.UtcNow;
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedOn = now;
}
else
{
if (entry.Property(p => p.CreatedOn).CurrentValue == DateTime.MinValue)
{
var original = entry.Property(p => p.CreatedOn).OriginalValue;
entry.Property(p => p.CreatedOn).CurrentValue = original != SqlDateTime.MinValue ? original : now;
entry.Property(p => p.CreatedOn).IsModified = true;
}
}
entry.Entity.LastModified = now;
}
我我正在寻找更通用的解决方案
谢谢你的'Upsert'方法工作的很好,这正是我所期待的! – Jcl 2014-09-19 10:02:51
我已经修改了更新,以便它检查属性的值不是相同的值(对于基元/值/字符串类型),所以如果它们的值相同,并且它们不会将实体标记为“已修改” Unchanged'。为了播种的目的,我相信这会更好。 在我的问题的具体情况下,这使得它始终不修改'LastModified' – Jcl 2014-09-19 11:06:24
@JCL,你是对的,这可以防止不必要的更新。我相应地更新了答案 – 2014-09-19 11:56:56