locked
How to track changes to an entity for audit purposes? RRS feed

  • Question

  • If one needs to create an audit trail of the changes made to entites - what is the best way?  So i have a table, say product,  exposed via EF+WCF and I have a WPF application where I have a text box bound 'TwoWay' to the product.price property of the product entity and I call save method on the data context. I will like to log in a separte audit table that a change was made to price of a certain product by a certain user.

    What will be the best way to do it?

    I have these thoughts-

    1. I could write a change intercept on the 'Products' entity in the WCF data service and in the function - get the current database value of the price - compare the new valuse and if different, make an entry in the audit table. Drawback is that the audit will be written before the actual change to the main product table - which could fail so the audit enetry will be wrong.

    2. I could do all the work in the client - make a note of all the changed values of the product properties and after the product table was updated, call another method to make audit entries. BTW what will be best way to keep track of properties which are changed (price,.......)? And how can one do it in a transaction so main table updates and audit changes go in as 'all or nothing'?

    drawback here is that if every client application needs to implement this logic - any calls directly to the Data service will not be audited. But this may be allowed if the dataservice can  be protected.

    Is there a design pattern for this kind of requirements?

    Thanks for your input.


    Thursday, June 2, 2011 3:44 PM

Answers

  • Hi,

    The interceptor approach is probably easier and it's not necessarily true that the changes to the audit table will go to DB before the rest of the changes. If you use EF to access/update your audit table as well, and you use the same context as the rest of the service and you don't call SaveChanges yourself, but you let the WCF DS do that for you, then your changes to the audit table will go in along with the rest of the changes requested by the client.

    You could also wrap the whole thing in a transaction using processing pipeline, to get the same behavior on the DB level.

    Thanks,


    Vitek Karas [MSFT]
    Monday, June 6, 2011 8:55 AM
    Moderator

All replies

  • Othe server you can create a partial class for the entity model and implement the partial void OnContextCreatd and hook the SavingChanges event.  From there you can lookp throgh the ObjectStateManager.GetObjectStateEntries() to get all the entries that have been modified.  You can see the before/after and decide what to audit.  Using this method anywhere the entity context is used you will get the audit hooks.

     

     

    Thursday, June 2, 2011 4:36 PM
  • Thanks for the pointers. I am going to going to follow the directions and see where I get.

    I had hoped that there will be already some need and hence code out there by now.

     

     

    Sunday, June 5, 2011 1:56 PM
  • Hi,

    The interceptor approach is probably easier and it's not necessarily true that the changes to the audit table will go to DB before the rest of the changes. If you use EF to access/update your audit table as well, and you use the same context as the rest of the service and you don't call SaveChanges yourself, but you let the WCF DS do that for you, then your changes to the audit table will go in along with the rest of the changes requested by the client.

    You could also wrap the whole thing in a transaction using processing pipeline, to get the same behavior on the DB level.

    Thanks,


    Vitek Karas [MSFT]
    Monday, June 6, 2011 8:55 AM
    Moderator
  • Hi RobinRaul,

    I am writing to check the status of the issue on your side.  Would you mind letting us know the result of the suggestions?

    If you need further assistance, please feel free to let me know.   I will be more than happy to be of assistance.

    Have a nice day.


    Alan Chen[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, June 8, 2011 2:46 AM
    Moderator
  • I am still in the process - I will let you know. If you have any more reading material and concrete code that would be helpful.

    I will update you. thanks.

    Thursday, June 9, 2011 6:50 PM
  • So if I add (psuedo) code in the change interceptor like this below in bold for Audit table adds using the 'current context' that change will go in along with the main product change? No need to call saveChanges?

     

    [ChangeInterceptor("Products")]
    public void OnChangeProducts(Product product, UpdateOperations operations)
    {
        if (operations == UpdateOperations.Change)
        {
            System.Data.Objects.ObjectStateEntry entry;

            if (this.CurrentDataSource.ObjectStateManager
                .TryGetObjectStateEntry(product, out entry))
            {
                 var _audit_entry = new audit_entrie();  //assume I have an entity of type audit_entry

                _audit_entry.user = "username";

               _audit_entry.description = "data changed from " + entry.originalvalues("productname") + "to " + entry.currentValues("ProductName");

                this.currentDataSource.addAudit_entries(_audit_entry);      

     

            }
            else
            {
                throw new DataServiceException(string.Format(
                    "The requested {0} could not be found in the data source.", product.ToString()));
            }
        }


    Thursday, June 9, 2011 8:04 PM
  • I have verified that the code as above works fine.

     

    Thanks.

     

    Robin

    Friday, June 10, 2011 7:21 PM