Wednesday 26 November 2008

DynamicData - Automatic Column Update For Entity Framework

Update to DynamicData - Automatic Column Update

See also the MSDN referance here:

How to: Execute Business Logic During Property Changes (Entity Framework)
How to: Execute Business Logic When Saving Changes (Entity Framework)
How to: Change Relationships Between Objects (Entity Framework)

namespace NorthwindModel
{

    public partial class NorthwindEntities
    {
        partial void OnContextCreated()
        {
            this.SavingChanges += new EventHandler(OnSavingChanges);
        }

        private static void OnSavingChanges(object sender, EventArgs e)
        {

            // This will populate the PasswordHash and PasswordSalt fields
            var stateManager = ((NorthwindEntities)sender).ObjectStateManager;
            var insertedEntities = stateManager.GetObjectStateEntries(EntityState.Added);

            foreach (ObjectStateEntry stateEntryEntity in insertedEntities)
            {
                if (stateEntryEntity.Entity is Customers)
                {
                    Customers cust = (Customers)stateEntryEntity.Entity;
                    cust.CreatedBy = HttpContext.Current.User.Identity.Name;
                    cust.CreatedOn = DateTime.Now;
                    cust.UpdatedBy = HttpContext.Current.User.Identity.Name; 
                    cust.UpdatedOn = DateTime.Now;
                }
            }

            var modifiedEntities = stateManager.GetObjectStateEntries(EntityState.Modified);
            foreach (ObjectStateEntry stateEntryEntity in modifiedEntities)
            {
                if (stateEntryEntity.Entity is Customers)
                {
                    Customers cust = (Customers)stateEntryEntity.Entity;
                    cust.UpdatedBy = HttpContext.Current.User.Identity.Name; 
                    cust.UpdatedOn = DateTime.Now;
                }
            }
        }
    }
}

In the above code the CreatedBy, CreatedOn, UpdateBy and UpdatedOn properties are automatically updated every time a record is modified or UpdateBy and UpdatedOn are modified when a record is updated.

Originally posted on ASP.Net Forum by Rick Anderson here Re: Setting a scaffolded column value

10 comments:

Yitzhak Khabinsky said...

Hi Stephen ,

What about the Delete operation?
I am getting an error there trying to apply the same idea as in your post.
"The object is in a detached or deleted state. An ObjectStateEntry in this state cannot be modified."

The following link provides all the details:
https://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=4203511&SiteID=1

Thank you in advance,
Yitzhak

Stephen J. Naughton said...

Hi Yitzhak, in Linq to SQL you have the DeleteCustomer(Customer instance) which you can override you could then pass the info you want into a sproc that does the delete or as I thin you intend just mark as deleted.

Steve :D

Yitzhak Khabinsky said...

Hi Stephen,

We are using Entity Framework (not the LINQ to SQL) for ASP.NET Dynamic Data plus stored procedures. So I have to pass somehow a User name as a parameter to a stored procedure. For the obvious reasons the User name is not exposed to the user interface (UI).

And you are right, this is needed for the following scenarios:

- logical delete, this is where you must have a stored proc and user name as a parameter.
- audit trail functionality for all Insert/Update/Delete operations
- stored procedure which accepts an arbitrary parameter which in turn is not mapped to an Entity.

Do you have any idea what could be done with the current limitations of the EF v.1 upon us?

Regards,
Yitzhak

Stephen J. Naughton said...

I would ask this question on EF forums. be specific (don't mention DD) just about passing username to SPROC for logical delete.

Sorry I'm not an EF expert yet L2S seems much more the thing even though they were developed in the same company they differ enought to make porting from one to the other a real pian. :(

Sorry again
Steve

Anonymous said...

Exactly what I was looking for! Thanks.

Craig Fisher said...

I'm doing pretty much the same sort of thing. However I don't want a dependency upon HttpContext in my model code - it should be able to run in any context (e.g. unit tests). So I'm setting a currentUser property on the ObjectContext on creation and then accessing that from the OnSavingChanges method.

Stephen J. Naughton said...

Thanks Craig, I'm going to be looking for a more generic approach like this one here
A Method to Handle Audit Fields in LINQ to SQL but for EF this should be made easyer in EF v4

Steve :D

Anonymous said...

Hi Stephen, very insightful article! could you help me with this one? i wonder how you would restrict updates on certain columns? i have this eight columns table where during when i make an update to just one of the columns, through the SQL Profiler, all others gets updated as well even though values are the same. Is there a way to prevent this as it is important i check the columns changes thru the UPDATE() function in SQL? many thanks...

james

Stephen J. Naughton said...

I think the only easy way would be to update via SPROC and I'm no EF expert on this, I know that it is possible in EF4 but not sure about EF1

Steve

Anonymous said...

Thank you.

I'm using EF4, but I don't find a good solution. I tried to set the Object to the OrginalValiues, but they are not available if the deletion is executed.

I think the easiest way ist to implement a own update, wich sets the flag.