I am using Nettiers with Codesmith 5.2
I have a bunch of classes/tables with the following columns:
CreatedOn - Datetime - system date. Represents the date time of when the record was created
CreatedBy - NVarchar(30) - userid of the logged in user that created the record
ModifiedOn - Datetime - system date. Represents the date time of when the record was updated last.
ModifiedBy - NVarchar(30) - userid of the logged in user that updated the record the last time
How do I set these column values before saving objects? The four columns may or may not be there on the table. But they are, all four columns with the same names as documented above will be there.
Thanks in advance.
I'd like to accomplish this generically by updating Codesmith Templates and/or writing some generic code.
You can see a discussion on this here:
http://community.codesmithtools.com/forums/p/9266/34328.aspx
Nettiers doesn't support this out of the box. You would have to modify the templates in order for this to work.
jeff
---------------------------------------------------------------------- Member of the .NetTiers team | Visit http://www.nettiers.com----------------------------------------------------------------------
I am thinking about modifying the EntityProviderBaseCore.generated.cst file and using reflection. The changed code is in bold
public virtual Entity Save(TransactionManager mgr, Entity entity) { switch ( entity.EntityState ) { case EntityState.Deleted: Delete(mgr, entity); break; case EntityState.Changed: //get a list of all table columns String[] Cols = entity.TableColumns; //check if the column createdby exists //using reflection set the column value Update(mgr, entity); break; case EntityState.Added: //get a list of all table columns String[] Cols = entity.TableColumns; //check if the column createdby exists //using reflection set the column value Insert(mgr, entity); break; } return entity; }
public virtual Entity Save(TransactionManager mgr, Entity entity) { switch ( entity.EntityState ) { case EntityState.Deleted: Delete(mgr, entity); break; case EntityState.Changed: //get a list of all table columns String[] Cols = entity.TableColumns; //check if the column createdby exists
//using reflection set the column value Update(mgr, entity); break; case EntityState.Added:
//get a list of all table columns String[] Cols = entity.TableColumns; //check if the column createdby exists
//using reflection set the column value Insert(mgr, entity); break; } return entity; }
Am I on the right track?
This is what I have for the code changes. I added a private method called SetAuditColmns.
public virtual Entity Save(TransactionManager mgr, Entity entity) { switch ( entity.EntityState ) { case EntityState.Deleted: Delete(mgr, entity); break; case EntityState.Changed: SetAuditColumns(entity); Update(mgr, entity); break; case EntityState.Added: SetAuditColumns(entity); Insert(mgr, entity); break; } return entity; }
This is my new method.
/// <summary> /// Sets audit column values /// </summary> /// <param name="entity"></param> /// <param name="entState"></param> private void SetAuditColumns(Entity entity) {
Type MyEntityType = typeof(Entity); System.Reflection.FieldInfo CreatedOnFieldInfo = MyEntityType.GetField("createdOn"); EntityState entState = entity.EntityState;
DateTime ServerDateTime = NextGenDateUtil.ServerDateTime();
if (CreatedOnFieldInfo != null) { CreatedOnFieldInfo.SetValue(entity, ServerDateTime); }
if (entState == EntityState.Changed) { System.Reflection.FieldInfo ModifiedOnFieldInfo = MyEntityType.GetField("modifiedOn");
if (ModifiedOnFieldInfo != null) { ModifiedOnFieldInfo.SetValue(entity, ServerDateTime); }
} }
When I debug my code, CreatedOnFieldInfo and ModifiedByFieldInfo always are null in both on the entity as well as its base class. Using the ILDASM tool, I found that the columns (createdOn and modifiedOn) exist on the base class but those are not accesible via reflective methods.
What am I missing?
Hello,
Since you have then entity itself why don't you just set the values that it should be without reflection?
entity.CreatedOn = DateTime.Now?
Thanks
-Blake Niemyjski
Blake Niemyjski CodeSmith Tools, LLC. Software Development Engineer Blog: http://windowscoding.com/blogs/blake/ .NetTiers team | Visit http://www.nettiers.com
Because not all entities will have createdon field. Thats why I have to do this reflectively.
I think I found a solution. And I have tested that it works. Can you confirm that this method will always be called whenever an entity is being saved?
/// <summary> /// Sets audit column values /// This method is called from the save method only if /// the entity state is added or updated /// </summary> /// <param name="entity">The entity that is being created or updated</param> private void SetAuditColumns(Entity entity) { //pull the server date DateTime ServerDateTime = NextGenDateUtil.ServerDateTime();
//build a local array that will be used to invoke methods reflectively Object[] InputParms = { ServerDateTime };
EntityState entState = entity.EntityState;
//get the type of the entity Type MyEntityType = typeof(Entity);
//set the created on only if this is a new entity if (entState == EntityState.Added) { //get the created on setter property reflectively MethodInfo MethodSetCreatedOn = MyEntityType.GetMethod("set_CreatedOn");
if (MethodSetCreatedOn != null) { MethodSetCreatedOn.Invoke(entity, InputParms); } }
//get the modified setter property reflectively MethodInfo MethodSetModifiedOn = MyEntityType.GetMethod("set_ModifiedOn");
//modified on will be set in both added and updated entity state scenarios if (MethodSetModifiedOn != null) { MethodSetModifiedOn.Invoke(entity, InputParms); }
}
It should as long as you are calling Save for that specific entity.
Thanks. In other words, as long as the we use Nettiers Save or DeepSave, we'll be fine. Is that correct?
It should work as long as you call Save, I would create a unit test for this to make sure that after each regeneration this is still working.
Thanks. Two additional questions.
1. I am trying modify the templates to incorporate these changes. The source file I changed for my testing is 'EntityProviderBaseCore.generated.cs'. Looks like the closest template to change is 'EntityProviderBaseCoreClass.generated.cst' and not EntityProviderBaseCore.generated.cst. Is this because this is a partial class? Is this the right template to change?
2. Based on all the testing I have done, looks like my code is being called whether the developer called DeepSave or Save on any object. So as long as the developers use Nettiers to save objects (save or deepsave), we should be fine. Am I correct?
These templates are not documented, we have fixed this in .netTiers 3.0. The only way to check this is to look up the interfaces and regions defined in the code and find the matching template.
Yes you are correct.
Thanks. I got all my answers. I have changed the SetAuditColumns method slightly.
Let me summarize the solution.
1. Edit the 'EntityProviderBaseCoreClass.generated.cst' in "../netTiers Templates/DataAccessLayer/Bases" to include these two changes:
a. Add a new method
private void SetAuditColumns(Entity entity) { //pull the server date DateTime ServerDateTime = NextGenDateUtil.ServerDateTime();
//pull the logged in user name from the config settings String UserName = System.Configuration.ConfigurationManager.AppSettings["LoggedinUser"].ToString();
//get the type of the entity Type MyEntityType = entity.GetType();
//set the created on only if this is a new entity if (entState == EntityState.Added) { //set the created on property PropertyInfo CreatedOn = MyEntityType.GetProperty("CreatedOn");
if (CreatedOn != null) { CreatedOn.SetValue(entity, ServerDateTime, null); }
//set the userid PropertyInfo CreatedBy = MyEntityType.GetProperty("CreatedBy"); if (CreatedBy != null) { CreatedBy.SetValue(entity, UserName, null); }
//get the modified setter property reflectively PropertyInfo ModifiedOn = MyEntityType.GetProperty("ModifiedOn");
//modified on will be set in both added and updated entity state scenarios if (ModifiedOn != null) { ModifiedOn.SetValue(entity, ServerDateTime, null); }
//set the userid PropertyInfo ModifiedBy = MyEntityType.GetProperty("ModifiedBy");
if (ModifiedBy != null) { ModifiedBy.SetValue(entity, UserName, null); }
b. Called this method from Save method.
public virtual Entity <%= MethodNames.Save %>(TransactionManager mgr, Entity entity) { switch ( entity.EntityState ) { case EntityState.Deleted: <%= MethodNames.Delete %>(mgr, entity); break; case EntityState.Changed: SetAuditColumns(entity); <%= MethodNames.Update %>(mgr, entity); break; case EntityState.Added: SetAuditColumns(entity); <%= MethodNames.Insert %>(mgr, entity); break; } return entity; }
thanks
robert
web:Blackberry 9900 battery