实体框架 - 审计活动 [英] Entity Framework - Auditing activity

查看:127
本文介绍了实体框架 - 审计活动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My database has a 'LastModifiedUser' column on every table in which I intend to collect the logged in user from an application who makes a change. I am not talking about the database user so essentially this is just a string on each entity. I would like to find a way to default this for each entity so that other developers don't have to remember to assign it any time they instantiate the entity.

所以有些东西这样会发生:

So something like this would occur:

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();
}


推荐答案

有一个完美的方法通过利用 在EF 4.0中完成此任务ObjectStateManager



首先,您需要为您的ObjectContext创建一个部分类,并订阅
< a href =http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.savingchanges.aspx =noreferrer> ObjectContext.SavingChanges事件 。订阅此事件的最佳位置在OnContextCreated方法中。该方法由上下文对象的构造函数和构造函数重载调用,这是一个没有实现的部分方法:

There is a perfect way to accomplish this in EF 4.0 by leveraging ObjectStateManager

First, you need to create a partial class for your ObjectContext and subscribe to ObjectContext.SavingChanges Event. The best place to subscribe to this event is inside the OnContextCreated Method. This method is called by the context object’s constructor and the constructor overloads which is a partial method with no implementation:

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



现在要做的工作的实际代码:


Now the actual code that will do the job:

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());
            }
        }
    }
}

strong>代码说明:


此代码查找任何具有 LastModifiedUser 已修改 / em>属性,然后使用您的定制 Lookupuser()方法的值更新该属性。



在foreach块中,查询基本演练到 CurrentValues 。然后,使用 Where 方法,它会查看每个 FieldMetaData 项目,仅拾取那些 名称 是LastModifiedUser
。接下来,if语句验证 LastModifiedUser 属性是一个 String 字段;那么它会更新该字段的值。




连接此方法(而不是订阅 SavingChanges 事件)的另一种方式是覆盖 ObjectContext.SaveChanges方法




顺便说一句,上述代码属于 Julie Lerman 从她的编程实体框架 书。






自我跟踪POCO实施编辑



如果您有自我跟踪POCO,那么我将做的是我先改变T4模板以调用OnContextCreated()方法。如果你看看你的ObjectContext.tt文件,那么所有的构造函数都调用一个 Initialize()方法,所以我们调用OnContextCreated()方法是一个很好的候选者,所以我们只需要做的就是更改ObjectContext.tt文件,如下所示:

Code Explanation:
This code locates any Added or Modified entries that have a LastModifiedUser property and then updates that property with the value coming from your custom Lookupuser() method.

In the foreach block, the query basically drills into the CurrentValues of each entry. Then, using the Where method, it looks at the names of each FieldMetaData item for that entry, picking up only those whose Name is LastModifiedUser. Next, the if statement verifies that the LastModifiedUser property is a String field; then it updates the field's value.

Another way to hook up this method (instead of subscribing to SavingChanges event) is by overriding the ObjectContext.SaveChanges Method.

By the way, the above code belongs to Julie Lerman from her Programming Entity Framework book.


EDIT for Self Tracking POCO Implementation:

If you have self tracking POCOs then what I would do is that I first change the T4 template to call the OnContextCreated() method. If you look at your ObjectContext.tt file, there is an Initialize() method that is called by all constructors, therefore a good candidate to call our OnContextCreated() method, so all we need to do is to change ObjectContext.tt file like this:

private void Initialize()
{
    // Creating proxies requires the use of the ProxyDataContractResolver and
    // may allow lazy loading which can expand the loaded graph during serialization.
    ContextOptions.ProxyCreationEnabled = false;
    ObjectMaterialized += new ObjectMaterializedEventHandler(HandleObjectMaterialized);
    // We call our custom method here:
    OnContextCreated();
}

这将导致在创建上下文时调用OnContextCreated() 。




现在,如果将您的POCO置于服务边界之后,则表示 ModifiedUserName 必须与其余数据一起提供您的WCF服务消费者。您可以将这个
LastModifiedUser 属性公开给他们进行更新或者存储在另一个属性中,并希望从该属性更新 LastModifiedUser ,然后您可以修改第二个代码如下:

And this will cause our OnContextCreated() to be called upon creation of the Context.

Now if you put your POCOs behind the service boundary, then it means that the ModifiedUserName must come with the rest of data from your WCF service consumer. You can either expose this LastModifiedUser property to them to update or if it stores in another property and you wish to update LastModifiedUser from that property, then you can modify the 2nd code as follows:


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());
        }
    }
}



希望这有帮助。


Hope this helps.

这篇关于实体框架 - 审计活动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆