我写一个asp.net应用mvc4和我使用实体框架5.我的每一个实体都像场EnteredBy
,EnteredOn
,LastModifiedBy
和LastModifiedOn
。
我正在尝试通过使用SavingChanges
事件自动保存它们。下面的代码已从众多博客,SO答案等中汇总到一起。
public partial class myEntities : DbContext
{
public myEntities()
{
var ctx = ((IObjectContextAdapter)this).ObjectContext;
ctx.SavingChanges += new EventHandler(context_SavingChanges);
}
private void context_SavingChanges(object sender, EventArgs e)
{
ChangeTracker.DetectChanges();
foreach (ObjectStateEntry entry in
((ObjectContext)sender).ObjectStateManager
.GetObjectStateEntries
(EntityState.Added | EntityState.Modified))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("LastModifiedBy") > 0)
{
HttpContext currContext = HttpContext.Current;
string userName = "";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currContext.Session["userId"] != null)
{
userName = (string)currContext.Session["userName"];
}
else
{
userName = currContext.User.Identity.Name;
}
}
entryValues.SetString(
entryValues.GetOrdinal("LastModifiedBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("LastModifiedOn"), now);
if (entry.State == EntityState.Added)
{
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), now);
}
else
{
string enteredBy =
entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"));
DateTime enteredOn =
entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"));
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"),enteredBy);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), enteredOn);
}
}
}
}
}
}
我的问题是,entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"))
并且entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"))
没有返回原始值,而是返回当前值null
。我对实体中的其他字段进行了测试,它们将返回以html形式输入的当前值。
我如何在这里获得原始值?
我认为问题可能是您使用模型绑定程序提供的实例作为控制器方法的输入,因此EF对该实体及其原始状态一无所知。您的代码可能如下所示:
public Review Update(Review review)
{
_db.Entry(review).State = EntityState.Modified;
_db.SaveChanges();
return review;
}
在这种情况下,EF对于Review
正在保存的实例一无所知。它信任您并将其设置为修改状态,因此它将所有属性保存到数据库中,但是它不知道该实体的原始状态\值。
检查本教程中名为“实体状态”的部分以及“附加和保存更改方法” 。您还可以检查本文的第一部分,该部分说明EF如何不了解原始值,并将更新数据库中的所有属性。
由于EF需要了解原始属性,因此您可以首先从数据库中加载您的实体,然后使用控制器中接收到的值更新其属性。像这样的东西:
public Review Update(Review review)
{
var reviewToSave = _db.Reviews.SingleOrDefault(r => r.Id == review.Id);
//Copy properties from entity received in controller to entity retrieved from the database
reviewToSave.Property1 = review.Property1;
reviewToSave.Property2 = review.Property2;
...
_db.SaveChanges();
return review;
}
这样做的好处是,仅修改后的属性将在数据库中发送和更新,并且视图和视图模型不需要公开业务对象中的每个字段,只需公开那些可由用户更新的字段。(打开具有viewModels和models \ business对象的不同类的门)。明显的缺点是您将对数据库造成额外的损失。
我在上面引用的教程中提到的另一个选项是让您以某种方式保存原始值(隐藏字段,会话等),并在保存时使用原始值将实体未经修改地附加到数据库上下文。然后使用已编辑的字段更新该实体。但是,除非您确实需要避免额外的数据库命中,否则我不建议您使用这种方法。
希望对您有所帮助!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句