Home  /  Questions  /  Question



50   50
Jul 09, 2014


Why are audit columns excluded from class definition?

In your Spark documentation on Page 42 you mention thefollowing: “If you have an Order table to represent orders, don’t rely on theCreatedOn column to determine the date of the order; instead include a separateOrderDate”

What was the reason for not including audit columns in theclass definition itself and use them straight away? For instance in the case ofArtist class in Domain.CS you have defined this class without four audit columnsbut the database definition itself has these four columns. Why did you excludethe following columns

        public System.DateTime CreatedOn { get; set; }

        public int? CreatedBy { get; set; }

        public System.DateTime ChangedOn { get; set; }

        publicint? ChangedBy { get; set; }

in class definition itself.How would you make use of audit columns in your program? The only possible way which comes to my mind is querying the database straight away like the following (In the case of CreatedOn column for instance):

Define a new property on Artist class called [CreatorName :Please note I didn't even call it CreatedOn to avoid possible future conflict with audit columns] as follows :

        public string CreatorName {get{ return ArtContext.Scalar("select a.FirstName+ ' ' + a.LastName from [user] ainner join artist b on a.Id = b.CreatedBy where a.Id = @0",parms:1).ToString();}}  

If above is the intended solution, wouldn't it be easier tohave all those four fields included in the class definition (just like other columns) and populate them along with other class members rather than relyingon extra fields which should be populated at run time?

Update 1:
King Wilder: I created a class called AuditData as follows:

    public sealed class AuditData

    {

        public string CreatedBy { get; set; }

 

        public DateTime CreatedDate { get; set; }

 

        public string UpdatedBy { get; set; }

 

        public DateTime UpdatedDate { get; set; }

    }

And now inside the Artist I have added a property as follows:

        public AuditData AudiData

        {

            get

            {

                const string sql = @"SELECT (SELECTFirstName+ ' ' + LastName FROM [User] WHERE Id = b.CreatedBy) AS CreatedBy,b.CreatedOn AS CreatedDate,

                                               (SELECTFirstName+ ' ' + LastName FROM [User] WHERE Id = b.ChangedBy) ASUpdatedBy,b.ChangedOn AS UpdatedDate FROM [Artist] b WHERE b.Id = @0";

               

                var temp = ArtContext.GetDataRow(sql, parms:Id);

 

                var data = new AuditData

                                 {

                                     CreatedBy = temp.Field<string>("CreatedBy"),

                                    CreatedDate = temp.Field<DateTime>("CreatedDate"),

                                     UpdatedBy = temp.Field<string>("UpdatedBy"),

                                    UpdatedDate = temp.Field<DateTime>("UpdatedDate")

                                 };

 

                return data;

            }

        }

You suggest moving this property to the base class in which this entity is derived from to avoid SRP violation? Irrespective of where this property is located something like above is required, right? I don’t understand why above violates SRP? How do you populate AuditData? I need to be able to display audit data to the user and auditing facility is quite important for me.

 





Kind regards,







588   99.9
Jul 09, 2014
I'm not responding to the first part of your question about why they didn't use the audit columns because I don't know why they didn't use them, but I will respond to your last question on including them into the class definition.

Yes, the audit properties should be in the class definition, but not directly.  Instead create a base class that all business object inherit that contains these common properties.  It's easier to maintain and works the same.

Next DON'T populate the property the way you have shown by have a data context query!  I would either follow their example and have the CreatedBy and ChangedBy properties be integers for the modifying users Id, or a string and enter their username.  No need to actually put in their name.  If you need the users real name for display purposes, create another property for it and simply populate it as you would any other property on the class.  Never have any type of data access query inside the property.  It's not flexible and breaks the Single Responsibility Principle (SRP).

I hope this helps.
 1 comment
 
King Wilder: I updated the question. Code sample of your solution is kindly appreciated. In addition you were saying :&quot; I would either follow their example and have the....&quot;. Which sample in which application? Spark sample application doesn&#39;t demonstrate auditing in depth. --- Jack Parker  Jul 09, 2014