Entity framework 实体框架-审计活动

Entity framework 实体框架-审计活动,entity-framework,entity,auditing,Entity Framework,Entity,Auditing,我的数据库在每个表上都有一个“LastModifiedUser”列,我打算在其中从进行更改的应用程序收集登录用户。我不是说数据库用户,所以本质上这只是每个实体上的一个字符串。我想找到一种为每个实体设置默认值的方法,以便其他开发人员在实例化实体时不必记住分配它 这样的事情就会发生: using (EntityContext ctx = new EntityContext()) { MyEntity foo = new MyEntity(); // Trying to avoid

我的数据库在每个表上都有一个“LastModifiedUser”列,我打算在其中从进行更改的应用程序收集登录用户。我不是说数据库用户,所以本质上这只是每个实体上的一个字符串。我想找到一种为每个实体设置默认值的方法,以便其他开发人员在实例化实体时不必记住分配它

这样的事情就会发生:

using (EntityContext ctx = new EntityContext())
{
    MyEntity foo = new MyEntity();

    // Trying to avoid having the following line every time
    // a new entity is created/added.
    foo.LastModifiedUser = Lookupuser(); 

    ctx.Foos.Addobject(foo);
    ctx.SaveChanges();
}

在EF4.0中,有一种通过利用

首先,需要为ObjectContext创建一个分部类并订阅 。订阅此事件的最佳位置是在OnContextCreated方法内。此方法由上下文对象的构造函数调用,构造函数重载是没有实现的部分方法:

partial void OnContextCreated() {
    this.SavingChanges += Context_SavingChanges;
}

现在,将执行此任务的实际代码:

void Context_SavingChanges(object sender, EventArgs e) {

    IEnumerable<ObjectStateEntry> objectStateEntries = 
        from ose 
        in this.ObjectStateManager.GetObjectStateEntries(EntityState.Added 
                                                         | EntityState.Modified)
        where ose.Entity != null
        select ose;

    foreach (ObjectStateEntry entry in objectStateEntries) {

        ReadOnlyCollection<FieldMetadata> fieldsMetaData = entry.CurrentValues
                .DataRecordInfo.FieldMetadata;

        FieldMetadata modifiedField = fieldsMetaData
            .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();

        if (modifiedField.FieldType != null) {

            string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;                    
            if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
                entry.CurrentValues.SetString(modifiedField.Ordinal, Lookupuser());
            }
        }
    }
}
这将导致在创建上下文时调用OnContextCreated()。

现在,如果您将POCO放在服务边界之后,那么这意味着ModifiedUserName必须与来自WCF服务使用者的其余数据一起提供。你可以公开这个 LastModifiedUser属性更新,或者如果它存储在另一个属性中,并且您希望从该属性更新LastModifiedUser,则可以修改第二个代码,如下所示:


foreach (ObjectStateEntry entry in objectStateEntries) {

    ReadOnlyCollection fieldsMetaData = entry.CurrentValues
            .DataRecordInfo.FieldMetadata;

    FieldMetadata sourceField = fieldsMetaData
            .Where(f => f.FieldType.Name == "YourPropertyName").FirstOrDefault();             

    FieldMetadata modifiedField = fieldsMetaData
        .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();

    if (modifiedField.FieldType != null) {

        string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
        if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
            entry.CurrentValues.SetString(modifiedField.Ordinal,
                    entry.CurrentValues[sourceField.Ordinal].ToString());
        }
    }
}


希望这能有所帮助。

现在有一个nuget软件包


Github

谢谢你的回答。我以前研究过这种模式,但无法启动onContextCreated事件。没问题。正如我所说,OnContextCreated不是一个事件,它只是一个没有实现的部分方法,由上下文对象的构造函数和构造函数重载调用。您所需要做的就是为您的上下文创建一个分部类,并将我的第一个代码片段放入其中。请这样做,让我知道它是如何为您工作的,如果它仍然不工作,我们将使它工作!事实上,我的想法是错误的,因此描述是错误的。让我完善我的问题。。。我们使用self-trackign实体,它们通过WCF服务提供给前端。当它们返回时,我们重新连接到上下文并保存。如果在拥有客户机时对其进行了修改,则lastModifiedUser需要反映这一点。服务器没有权限知道当前用户是谁,因此它不能负责设置用户。我假设在理论上我想在实体级别做一些类似于oncreated event/partial方法的事情?好的,现在我明白你的意思了。我更新答案以解决POCO情况。请试一试,上面的代码有点错误。测试
if(modifiedField.FieldType!=null)
应替换为
if(modifiedField!=null)

foreach (ObjectStateEntry entry in objectStateEntries) {

    ReadOnlyCollection fieldsMetaData = entry.CurrentValues
            .DataRecordInfo.FieldMetadata;

    FieldMetadata sourceField = fieldsMetaData
            .Where(f => f.FieldType.Name == "YourPropertyName").FirstOrDefault();             

    FieldMetadata modifiedField = fieldsMetaData
        .Where(f => f.FieldType.Name == "LastModifiedUser").FirstOrDefault();

    if (modifiedField.FieldType != null) {

        string fieldTypeName = modifiedField.FieldType.TypeUsage.EdmType.Name;
        if (fieldTypeName == PrimitiveTypeKind.String.ToString()) {
            entry.CurrentValues.SetString(modifiedField.Ordinal,
                    entry.CurrentValues[sourceField.Ordinal].ToString());
        }
    }
}