Search code examples
c#sql-serveref-code-firstintellisenseaudit-trail

How to implement covert SQL Records Change Audit-Trail


My company wanted to implement audits for a SQL Server database. The result of combining quite a few really good solutions found on SO I wound up with the following:

An interface:

public interface IAuditable
{
    string CreatedBy { get; set; }
    DateTime? CreatedDate { get; set; }
    string CreatedIpAddress { get; set; }
    string ModifiedBy { get; set; }
    DateTime? ModifiedDate { get; set; }
    string ModifiedIpAddress { get; set; }
}

A BaseClass that implements the interface. The annotations are supposed to hide the properties from the designer:

public abstract class BaseModel : IAuditable
{
    [Browsable(false)]
    [Bindable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string CreatedBy { get; set; }

    [Browsable(false)]
    [Bindable(false)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public DateTime? CreatedDate { get; set; }
    <snip>
    ...
    </snip>
}

A domain model that derives from the BaseClass:

public class Person : BaseModel
{
    public int Id { get; set; }

    public string FirstName { get; set; }
    public string LastName { get; set; }
}

I override SaveChanges() to populate the properties.

If I bind the collection to a datagridview it does not show these columns. However intellisense still offers them in a lambda Expression. How do I hide these properties from intellisense?

I have exposed the model to the UI (yes I know, bad practice). I was thinking of trying to hide these in what Julie Lerman calls a bounded context. But I think my SaveChanges() override won’t be able to populate the properties. OR I might need to push this to an SQL function like I do with SoftDelete. Any help will be appreciated.


Solution

  • Not quite sure why you would want to hide these from Intellisense, but you can implement your interface explicitly.

    public abstract class BaseModel : IAuditable
    {
        string IAuditable.CreatedBy { get; set; }
    
        DateTime? IAuditable.CreatedDate { get; set; }
    }
    

    These properties are still there, but will only be accessible in code if you are explicitly working with a variable or property defined as IAuditable.