LinqToSQL generic lookup of foreign key entity to string

Peter

I am working with Linq To Sql and am trying to keep a history of changes and store these database.

I know there are frameworks for this out there such as DoddleAudit but it feels too buggy and bloaty to me so I'm trying to create my own.

This is what I have this far. I am looking for a way to make the repetitive code more reuseable:

protected void InsertAuditRecordToDatabase(ModifiedMemberInfo[] changes, object entity) 
{
    Type type = entity.GetType();
    PropertyInfo key;
    key = type.GetProperties()
        .Where(o => 
            o.GetCustomAttributes(typeof(ColumnAttribute), true)
                .Any(a=>((ColumnAttribute)a).IsPrimaryKey)).SingleOrDefault();

    AuditRecord audit = new AuditRecord();
    audit.Action = (byte)AuditAction.Update;
    audit.AuditDate = DateTime.Now;
    audit.AssociationTable = null;
    audit.AssociationTableKey = null;
    audit.EntityTable = type.Name;
    audit.EntityTableKey = int.Parse(key.GetValue(entity, null).ToString());

    audit.UserName = HttpContext.Current.User.Identity.Name;
    if (string.IsNullOrEmpty(audit.UserName))
        audit.UserName = "Anonymous";

    foreach (ModifiedMemberInfo mmi in changes)
    {
        AuditRecordField field = new AuditRecordField();
        if (!excludedFieldNamesFromAudit.Any(x => x.Equals(mmi.Member.Name, StringComparison.OrdinalIgnoreCase)))
        {
            field.MemberName = mmi.Member.Name;

            field.OldValue = (mmi.OriginalValue != null ? mmi.OriginalValue.ToString() : string.Empty);
            field.NewValue = (mmi.CurrentValue != null ? mmi.CurrentValue.ToString() : string.Empty);

            if ((field.OldValue != null && !field.OldValue.Equals(field.NewValue)) ||
                (field.OldValue == null && field.NewValue != null))
            {
                // Special handling
                if (field.MemberName.Equals("EUAMemberTypeId"))
                {
                    int oldInt;
                    OrganisationSubType oldValue = null;
                    if(int.TryParse(field.OldValue, out oldInt))
                        oldValue = this.OrganisationSubTypes.SingleOrDefault(m => m.Id == oldInt);
                    field.OldValue = oldValue != null ? oldValue.Name : string.Empty;

                    int newInt;
                    OrganisationSubType newValue = null;
                    if(int.TryParse(field.NewValue, out newInt))
                        newValue = this.OrganisationSubTypes.SingleOrDefault(m => m.Id == newInt);
                    field.NewValue = newValue != null ? newValue.Name : string.Empty;
                }

                if (field.MemberName.Equals("ContactPersonStaffId"))
                {
                    int oldInt;
                    OrganisationStaff oldValue = null;
                    if (int.TryParse(field.OldValue, out oldInt))
                        oldValue = this.OrganisationStaffs.SingleOrDefault(m => m.Id == oldInt);
                    field.OldValue = oldValue != null ? oldValue.Contact.FullName : string.Empty;

                    int newInt;
                    OrganisationStaff newValue = null;
                    if (int.TryParse(field.NewValue, out newInt))
                        newValue = this.OrganisationStaffs.SingleOrDefault(m => m.Id == newInt);
                    field.NewValue = newValue != null ? newValue.Contact.FullName : string.Empty;
                }

                if (field.MemberName.Equals("CountryId"))
                {
                    int oldInt;
                    Country oldValue = null;
                    if (int.TryParse(field.OldValue, out oldInt))
                        oldValue = this.Countries.SingleOrDefault(m => m.Id == oldInt);
                    field.OldValue = oldValue != null ? oldValue.Name : string.Empty;

                    int newInt;
                    Country newValue = null;
                    if (int.TryParse(field.NewValue, out newInt))
                        newValue = this.Countries.SingleOrDefault(m => m.Id == newInt);
                    field.NewValue = newValue != null ? newValue.Name : string.Empty;
                }

                // Save it to the DB
                audit.AuditRecordFields.Add(field);
            }
        }
    }

    if (audit.AuditRecordFields.Count > 0)
        this.AuditRecords.InsertOnSubmit(audit);
}

As you can see, this block of code is being repeated:

if (field.MemberName.Equals("CountryId"))
{
    int oldInt;
    Country oldValue = null;
    if (int.TryParse(field.OldValue, out oldInt))
        oldValue = this.Countries.SingleOrDefault(m => m.Id == oldInt);
    field.OldValue = oldValue != null ? oldValue.Name : string.Empty;

    int newInt;
    Country newValue = null;
    if (int.TryParse(field.NewValue, out newInt))
        newValue = this.Countries.SingleOrDefault(m => m.Id == newInt);
    field.NewValue = newValue != null ? newValue.Name : string.Empty;
}

The repeated pattern is:

  • A lookup on a certain table: Countries
  • Looking for a certain entity: Country
  • Using a certain expression: m => m.ID == oldInt
  • And another expression to convert the entity to a string: oldValue.Name

I was hoping that this could be done with some generic expression magic but I can't seem to figure it out.

Grax32

This should work as you intend.

One of the challenges you face is that you expect to have the expression for the int parameter before the variable is created as you parse the string. If you already had the variable created at the time you created the expression, it could reference the variable and your process would be simpler.

I got around that by dynamically building an expression after the string is parsed into the int variable.

    protected void InsertAuditRecordToDatabase(ModifiedMemberInfo[] changes, object entity)
    {
        Type type = entity.GetType();
        PropertyInfo key;
        key = type.GetProperties()
            .Where(o =>
                o.GetCustomAttributes(typeof(ColumnAttribute), true)
                    .Any(a => ((ColumnAttribute)a).IsPrimaryKey)).SingleOrDefault();

        AuditRecord audit = new AuditRecord();
        audit.Action = (byte)AuditAction.Update;
        audit.AuditDate = DateTime.Now;
        audit.AssociationTable = null;
        audit.AssociationTableKey = null;
        audit.EntityTable = type.Name;
        audit.EntityTableKey = int.Parse(key.GetValue(entity, null).ToString());

        audit.UserName = HttpContext.Current.User.Identity.Name;
        if (string.IsNullOrEmpty(audit.UserName))
            audit.UserName = "Anonymous";

        foreach (ModifiedMemberInfo mmi in changes)
        {
            AuditRecordField field = new AuditRecordField();
            if (!excludedFieldNamesFromAudit.Any(x => x.Equals(mmi.Member.Name, StringComparison.OrdinalIgnoreCase)))
            {
                field.MemberName = mmi.Member.Name;

                field.OldValue = (mmi.OriginalValue != null ? mmi.OriginalValue.ToString() : string.Empty);
                field.NewValue = (mmi.CurrentValue != null ? mmi.CurrentValue.ToString() : string.Empty);

                if ((field.OldValue != null && !field.OldValue.Equals(field.NewValue)) ||
                    (field.OldValue == null && field.NewValue != null))
                {
                    // Special handling
                    if (field.MemberName.Equals("EUAMemberTypeId"))
                    {
                        field.OldValue = GetDescription(this.OrganisationSubTypes, field.OldValue, m => m.Id, m => m != null ? m.Name : string.Empty);
                        field.NewValue = GetDescription(this.OrganisationSubTypes, field.NewValue, m => m.Id, m => m != null ? m.Name : string.Empty);
                    }

                    if (field.MemberName.Equals("ContactPersonStaffId"))
                    {
                        field.OldValue = GetDescription(this.OrganisationStaffs, field.OldValue, m => m.Id, m => m != null ? m.Contact.FullName : string.Empty);
                        field.NewValue = GetDescription(this.OrganisationStaffs, field.NewValue, m => m.Id, m => m != null ? m.Contact.FullName : string.Empty);
                    }

                    if (field.MemberName.Equals("CountryId"))
                    {
                        field.OldValue = GetDescription(this.Countries, field.OldValue, m => m.Id, m => m != null ? m.Name : string.Empty);
                        field.NewValue = GetDescription(this.Countries, field.NewValue, m => m.Id, m => m != null ? m.Name : string.Empty);
                    }

                    // Save it to the DB
                    audit.AuditRecordFields.Add(field);
                }
            }
        }

        if (audit.AuditRecordFields.Count > 0)
            this.AuditRecords.InsertOnSubmit(audit);
    }

    public static string GetDescription<T, TProp>(Table<T> thisTable, string searchParam, Expression<Func<T, TProp>> searchExpression, Expression<Func<T, string>> descriptionExpression)
        where T : class
    {
        if (!(searchExpression.Body is MemberExpression))
        {
            throw new ArgumentException("Search Expression must be a MemberExpression (i.e v => v.Id)", "searchExpression");
        }
        else
        {
            int searchValue;
            if (int.TryParse(searchParam, out searchValue))
            {
                var equalityExpression = Expression.Equal(searchExpression.Body, Expression.Constant(searchValue));
                var lambdaExpression = Expression.Lambda<Func<T, bool>>(equalityExpression, searchExpression.Parameters);

                // the passed-in expression must resemble v => v.Id
                // the generated expression will resemble v => v.Id == 5

                var value = thisTable.SingleOrDefault(lambdaExpression);
                return descriptionExpression.Compile()(value);
            }

            return string.Empty;
        }
    }

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Filter Generic Foreign Key

From Dev

Django generic foreign key

From Dev

Foreign key with Entity Framework

From Dev

C# -> Entity Framework 6.1.3 -> Composite nullable foreign key string

From Dev

Django Generic Foreign Key Sorting

From Dev

Entity Framework - Foreign Key Constraint

From Dev

Mapped foreign key in Hibernate Entity

From Dev

Entity Framework, Unneeded Foreign key

From Dev

Entity Framework Foreign Key DataAnnotations

From Dev

How to prevent foreign key lookup in django

From Dev

Foreign Key Lookup Dropdownlist EF 6

From Dev

Reverse lookup of foreign key in python django

From Dev

sqlserver foreign key constraint on lookup table

From Dev

django foreign key lookup aggregate data

From Dev

INSERT conflicted with foreign key constraint for lookup table

From Dev

Persisting entity with foreign key to existing entity

From Dev

Persisting entity with foreign key to existing entity

From Dev

Entity Framework foreign key inserting duplicate key

From Dev

Primary key of Parent Entity not stored as Foreign Key in Child Entity

From Dev

Entity Framework define primary key as foreign key to another entity

From Dev

Entity Framework Code First Foreign Key issue

From Dev

Delete an entity without to delete the foreign key link to it

From Dev

Entity Framework Cascade delete - FOREIGN KEY constraint

From Dev

Entity Framework foreign key not found during migration

From Java

How to add foreign key relationship in Entity Framework?

From Dev

Entity Framework Foreign Key Error with Insert

From Dev

Entity Framework creates undesired foreign key column

From Dev

Code first foreign key association MVC Entity

From Dev

Two column foreign key in entity framework

Related Related

HotTag

Archive