实体框架 - 审计活动

发布于 2024-09-25 07:20:57 字数 465 浏览 0 评论 0原文

我的数据库在每个表上都有一个“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();
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

苏别ゝ 2024-10-02 07:20:57

在 EF 4.0 中,有一种完美的方法可以通过利用 来实现此目的ObjectStateManager

首先,您需要为 ObjectContext 创建一个分部类并订阅
ObjectContext.SavingChanges 事件 。订阅此事件的最佳位置是在 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());
            }
        }
    }
}

代码说明

此代码查找具有 LastModifiedUser 属性的任何添加修改条目,然后使用来自自定义Lookupuser的值更新该属性() 方法。

在 foreach 块中,查询基本上深入到 每个条目的当前值。然后,使用 Where 方法,它会查看每个 FieldMetaData 该条目的项目,仅选取那些 名称 LastModifiedUser。接下来,if 语句验证 LastModifiedUser 属性是否为 String 字段;然后它更新该字段的值。

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

顺便说一下,上面的代码属于 Julie Lerman,来自她的 < href="http://learnentityframework.com/learnentityframework/" rel="noreferrer">编程实体框架一本书。

编辑自我跟踪 POCO 实施:

如果您有自我跟踪 POCO,那么我要做的就是首先更改 T4 模板以调用 OnContextCreated() 方法。如果您查看 ObjectContext.tt 文件,会发现有一个由所有构造函数调用的 Initialize() 方法,因此是调用 OnContextCreated() 方法的一个很好的选择,因此我们需要做的就是像这样更改 ObjectContext.tt 文件:

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 ,那么您可以修改第二个代码,如下所示:


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

希望这有帮助。

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

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文