我在VS2010,POCO和模型优先方法中使用EF4。
我的实体具有以下属性:Id:Guid,Name:String,Created:DateTime,Modified:DateTime,Revision:Int32。
我创建我的实体,设置名称并使用EF4上下文将其保存到数据库。这应该将Id设置为新的Guid(与Identity-SGP一起使用),Created设置为now,Modified left as null,Revision设置为0.我检索实体,更改名称并再次保存。这次Modified-value应设置为now,revision应为1.
如何使用EF4与EDMX设计师最好地实现这一目标?
更新
这是我最终使用的:
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
foreach (ObjectStateEntry entry in ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Where(e => e.Entity is EntityBase))
{
EntityBase entity = entry.Entity as EntityBase;
if (entry.State == EntityState.Added)
{
entity.Version = new Version() { Major = 1, Minor = 0, Revision = 0 };
entity.Created = DateTime.Now;
if (OperationContext.Current != null) entity.CreatedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
}
else if (entry.State == EntityState.Modified)
{
entity.Version.Revision++;
entity.Modified = DateTime.Now;
if (OperationContext.Current != null) entity.ModifiedBy = OperationContext.Current.ServiceSecurityContext.WindowsIdentity.Name;
}
}
return base.SaveChanges(options);
}
哪个不起作用...... :(
问题是即使我明确地运行MarkAsModified()方法,entry.State仍然是未修改的。我不明白......
为什么默认情况下无法启用更改跟踪?我使用自我跟踪实体,为什么我要把它关闭并每次明确地打开它?为什么即使状态未经修改,实体仍然持有db?那么EntityState和ObjectState之间的区别是什么?目前我正在进行所有更改并更新服务器端,但我也将使用WCF服务来回传输实体一段时间......这里如何处理更改有什么不同?如果服务器端的所有更改,无论是开启/关闭更改,都会持续存在?我想要的是,在没有更新Modified,Revision等的情况下,任何东西都不能存储。当收到对象并且已经更改时,应始终在服务器上设置这些属性。 (我不是在这里谈论sql-server-side而是服务端服务器端)
答案 0 :(得分:3)
假设您的实体类型名称为Product:
partial void OnContextCreated() {
this.SavingChanges += Context_SavingChanges;
}
void Context_SavingChanges(object sender, EventArgs e) {
IEnumerable objectStateEntries =
from ose
in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added |
EntityState.Modified)
where ose.Entity is Product
select ose;
Product product = objectStateEntries.Single().Entity as Product;
product.ModifiedDate = DateTime.Now;
product.ComplexProperty.Revision++;
}
如果您希望使用此代码为所有实体填充公共字段(如ModifiedDate或ModifiedBy),请查看此帖子:
Entity Framework - Auditing Activity
顺便说一句, StoreGeneratedPattern 和 ConcurrencyMode 与此无关,它们适用于完全不同且无关的内容。
答案 1 :(得分:0)
我个人偏爱基于客户端代码的解决方案。由于您正在使用POCO,因此让对象本身进行更新可能是最简单的。更新Name属性上的set访问器以调用更改Modified和Revision属性的“objectModified”方法。
如果由于更改属性的时间与保存对象的时间之间的时间差而导致这种情况不合适,则可以使用Entities对象上的分部类。这样做将允许您覆盖SaveChanges方法,您可以在其中触摸您的ObjectSet< T>中的entites。实体对象上的属性。类似的东西:
public partial class YourEntities
{
public override int SaveChanges(System.Data.Objects.SaveOptions options)
{
//update your objects here
return base.SaveChanges(options);
}
}
答案 2 :(得分:0)
我们可以使用partial class并覆盖SaveChanges方法来实现这一点。
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace TestDatamodel
{
public partial class DiagnosisPrescriptionManagementEntities
{
public override int SaveChanges()
{
ObjectContext context = ((IObjectContextAdapter)this).ObjectContext;
foreach (ObjectStateEntry entry in
(context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("ModifiedBy") > 0)
{
HttpContext currentContext = HttpContext.Current;
string userId = "nazrul";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currentContext .Session["userId"] != null)
{
userId = (string)currentContext .Session["userId"];
}
else
{
userId = UserAuthentication.GetUserId(currentContext .User.Identity.UserCode);
}
}
if (entry.State == EntityState.Modified)
{
entryValues.SetString(entryValues.GetOrdinal("ModifiedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("ModifiedDate"), now);
}
if (entry.State == EntityState.Added)
{
entryValues.SetString(entryValues.GetOrdinal("CreatedBy"), userId);
entryValues.SetDateTime(entryValues.GetOrdinal("CreatedDate"), now);
}
}
}
}
return base.SaveChanges();
}
}
}