How to set properties for a shared object?

I want to check if an object has 3 properties. CreatedDate, ModifiedDate, and ModifiedBy.

Right now I'm just hard-coding those that I know have them in the SaveChanges () method of my object context.

For example:

bool newEntity = (entry.State == EntityState.Added); if (type == typeof(Foo)) { var r = entry.Entity as Foo; if (r != null) { if (newEntity) r.CreatedDate = DateTime.Now; r.ModifiedDate = DateTime.Now; r.ModifiedBy = HttpContext.Current.User.Identity.Name; } } 

I know that you can check if an object has a specific method using code like this:

 public static bool HasMethod(this object objectToCheck, string methodName) { var type = objectToCheck.GetType(); return type.GetMethod(methodName) != null; } 

But how can I get these properties without directly casting an object?

How can I do something like:

 if (HasMethod(entry.Entity)) entry.Entity.ModifiedDate = DateTime.Now; 

I am using ASP.Net MVC 4.

+7
source share
3 answers

You can use the method below. It will set the if exists property. Using GetType with every call can cause some overhead, it needs optimization.

  private void TrySetProperty(object obj, string property, object value) { var prop = obj.GetType().GetProperty(property, BindingFlags.Public | BindingFlags.Instance); if(prop != null && prop.CanWrite) prop.SetValue(obj, value, null); } 

Using

  TrySetProperty(entry.Entity, "ModifiedDate", DateTime.Now); 
+13
source

You can either use reflection, which several people have already mentioned, or create an interface. If you use automatically generated objects, they are defined using the partial keyword, so you can create another class file in the same project and give it the same namespace and class definition, and you can implement this interface. Then, in the code you indicated above, you check to see if the object implements your interface, if so, discards it, and then sets the values.

The advantage of the interface is that you do not use reflection (which can be an expensive operation), as well as any future objects that you create will work automatically, just implementing your interface.

In cases where your object properties do not match your interface, you can explicitly implement an interface that will handle any named violations.

Example: suppose you define an interface, IContainAuditProperties , and you have all your corresponding objects implementing this interface, you can do the following inside a block where you iterate over all your new / changed objects:

 var entity = entry.Entity as IContainAuditProperties; if(entity != null) { entity.CreatedDate = DateTime.Now; entity.ModifiedDate = DateTime.Now; //etc. } 
+6
source

You can check if the object has a public property with a specific name using this code:

 public static bool HasWritableProperty(this object objectToCheck, string propertyName) { var type = objectToCheck.GetType(); //get a property info for the property, but only if it is a public instance property var pi = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public) //return false if no propery is found if (pi==null) return false; //get the set method for the property var setter = pi.GetSetMethod(); //if it null the property is not writable return (setter != null); } 

However, this is not very efficient code, since it uses a lot of reflections.

If you go through this route, I will memorize the result of this code, so each check will be performed no more than once.

What I actually do in my projects (I use EF Code First) has a BaseEntity class that has common properties and has specific objects inherited from the BaseEntity class. Then I have a FillEntityMetadata method, more or less:

 protected void FillEntityMetadata(BaseEntity entity, bool isUpdate = false) { // Set audit data. if (!isUpdate) { entity.CreatedBy = CurrentUser.ID; entity.CreatedOn = DateTime.Now; entity.IsActive = true; } entity.LastModifiedBy = CurrentUser.ID; entity.LastModifiedOn = DateTime.Now; } 

Please note that for this you can also use the IBaseEntity interface, and it will work in exactly the same way.

+1
source

All Articles