Linq ExpressionTrees

I was faced with the following situation: I’ve entered a .NET/WPF project that was already running two years. My tasks were to maintain and improve the business and data access layer. The application had to deal with files and due to the fact that the Sql Server 2008 FileTable feature should NOT be used, we saved file references with the entities that were associated to files in the database. One entity could reference up to 14 different files.
At some point of time a new feature request arrived: Delete all files that are not referenced by an entity in the database from disk.

My solution:
I’ve been too lazy to code each database query to check whether the content of any property1 to property14 of table (entity) x contained a reference to an existing file. And what if another file reference property will be added in the future?
Instead I’ve implemented a FilePath attribute and decorated all the properties of the entity that represented FileReferences. With the help of Reflection and ExpreesionTrees I was able to construct database queries at runtime to query for columns that contained a file reference from disk.
This code example shows the basic idea:

public static class ExpressionExample
{
 public static void Do()
 {
   var someClassSuccess = new SomeClass { A = 2, B = "Hello" };
   var someClassNull = new SomeClass { A = 2 };
   var someClassFailure = new SomeClass { A = 2, B = "Foo" };

   typeof(SomeClass).GetProperties()
                    .Where(p => p.IsDefined(typeof(FilePathAttribute), false))
                    .ExecuteForEach(p =>
                    {
                      var expressionParameter = Expression.Parameter(typeof(SomeClass), "lambda");
                      var parameter = new [] { expressionParameter };
                      var propertyAccess = Expression.Property(expressionParameter, p);
                      var nullCheck = Expression.NotEqual(propertyAccess, Expression.Constant(null, p.PropertyType));
                      var nullCheckLambda = Expression.Lambda<Func<SomeClass, Boolean>>(nullCheck, parameter);

                      var containsMethodInfo = typeof(String).GetMethod("Contains", new[] { typeof(String) });
                      var contains = Expression.Call(propertyAccess, containsMethodInfo, Expression.Constant("ell"));
                      var containsLambda = Expression.Lambda<Func<SomeClass, Boolean>>(contains, new[] { expressionParameter });

                     var predicate = Expression.Lambda<Func<SomeClass, Boolean>>(
                                     Expression.AndAlso(nullCheckLambda.Body, containsLambda.Body), parameter);
                     Console.WriteLine(predicate.ToString());
                     Console.WriteLine("Success: " + predicate.Compile().Invoke(someClassSuccess));
                     Console.WriteLine("Null: " + predicate.Compile().Invoke(someClassNull));
                     Console.WriteLine("Failure: " + predicate.Compile().Invoke(someClassFailure));
                   });
 }

[AttributeUsage(AttributeTargets.Property)]
 class FilePathAttribute : Attribute
 {

 }

 class SomeClass
 {
    public int A { get; set; }

   [FilePath]
   public string B { get; set; }
 }
 }
Advertisements