Archive

Posts Tagged ‘LINQ’

Type Member Name Resolution with Functions – Part 2.0

June 16th, 2009 Simon Segal 1 comment

Adding to the previous post, the PropertyNameResolver class needs to expand it’s horizons and resolve method names and field names. Given the expanded requirement we probably need to refactor the name of the class to something more appropriate. Here is a more fleshed out idea of what it might look like:

public class MemberNameResolver<T>
{
    public static string ResolveProperty<TPropertyType>
        (Expression<Func<T, TPropertyType>> expression)
    {
        Func<Expression<Func<T, TPropertyType>>, string>
            prop_name_function = l =>
        {
            return GetNameFromExpression(l.Body);
        };
        var property_name =
            typeof(T).GetProperty(prop_name_function(expression)).Name;
        return property_name;
    }

    public static string ResolveMethod(Expression<Action<T>> expression)
    {
        Func<Expression<Action<T>>, string>
            prop_name_function = l =>
            {
                return GetNameFromExpression(l.Body);
            };
        var property_name =
            typeof(T).GetMethod(prop_name_function(expression)).Name;
        return property_name;
    }

    public static string ResolveField<TPropertyType>
        (Expression<Func<T, TPropertyType>> expression)
    {
        Func<Expression<Func<T, TPropertyType>>, string>
            prop_name_function = l =>
            {
                return GetNameFromExpression(l.Body);
            };
        var property_name =
            typeof(T).GetField(prop_name_function(expression)).Name;
        return property_name;
    }

    private static string GetNameFromExpression(Expression body)
    {
        if (ExpressionType.MemberAccess == body.NodeType)
        {
            var memberExpr = (MemberExpression)body;
            return memberExpr.Member.Name;
        }
        else if (ExpressionType.Call == body.NodeType)
        {
            var methodExpr = (MethodCallExpression)body;
            return methodExpr.Method.Name;
        }
        else
        {
            throw new NotImplementedException(
                string.Format(“Resolving names from expression types “ +
                “of {0} is not implemented!”,
                body.Type.Name));
        }
    }
}
Previously we did not account for method calls and as one kind soul articulately pointed out, the string manipulation was somewhat awkward. Mark pointed out Damien’s neat solution by way of digging into the expression body.

Notice the newly specialized Resolve methods now allow a usage like the following:

var member1 =
    MemberNameResolver<Criteria>
    .ResolveProperty<int>(c => c.PageCounter);
var member2 =
    MemberNameResolver<Criteria>
    .ResolveMethod(c => c.SomeMethod());
var member3 =
    MemberNameResolver<Criteria>
    .ResolveField(c => c.Percent);
var member4 =
    MemberNameResolver<Criteria>
    .ResolveMethod(c => c.SomeMethodWithArgs(default(string),
        default(int), default(string[])));

Console.WriteLine(member1);
Console.WriteLine(member2);
Console.WriteLine(member3);
Console.WriteLine(member4);

Producing the following output:

console_functions_memer_resolve1

Getting more out of Functions

So far the approach is a little static from a functional point of view so perhaps we could do this a little differently? If we define the following functions we get some equivalent behaviour to our utility class.

Func<Expression<Func<Criteria, int>>, Expression> criteriaFunction =
    c => c.Body;

Func<Expression, string> propertyResolverFunction = e =>
{
    if (ExpressionType.MemberAccess == e.NodeType)
    {
        var memberExpr = (MemberExpression)e;
        return memberExpr.Member.Name;
    }
    else if (ExpressionType.Call == e.NodeType)
    {
        var methodExpr = (MethodCallExpression)e;
        return methodExpr.Method.Name;
    }
    else
    {
        throw new NotImplementedException(
            string.Format(“Resolving names from expression types “ +
            “of {0} is not implemented!”,
            e.Type.Name));
    }
};

var propertyName =
    propertyResolverFunction(
        criteriaFunction(c => c.PageCounter));

Console.WriteLine(propertyName);

Here we have created two functions that can be used together to achieve our required end result. The first function criteriaFunction, takes a generic expression as an argument and returns an expression. The second function propertyResolverFunction, takes an expression as it’s argument and returns a string. By passing one function as an argument to the other, we achieve the same results as with the static utility class already demonstrated. To collapse this even further we can wrap up both those functions  into one.

Func<Expression<Func<Criteria, string>>, Func<Expression, string>> allInOne =
    c => e =>
    {

        if (ExpressionType.MemberAccess == e.NodeType)
        {
            var memberExpr = (MemberExpression)e;
            return memberExpr.Member.Name;
        }
        else if (ExpressionType.Call == e.NodeType)
        {
            var methodExpr = (MethodCallExpression)e;
            return methodExpr.Method.Name;
        }
        else
        {
            throw new NotImplementedException(
                string.Format(“Resolving names from expression types “ +
            “of {0} is not implemented!”,
                e.Type.Name));
        }
    };

Expression<Func<Criteria, string>> exp = c => c.Levels;
var property_name_allinone = allInOne(exp)(exp.Body);

Console.WriteLine(property_name_allinone);

When we call the allinone function with the expression argument, it returns a function that in turns take the body property of the same expression that was passed to the higher order function. All the code in the post presumes the the following class:

public class Criteria
{
    public decimal Percent;

    private int _pageCounter;

    public int PageCounter
    {
        get { return _pageCounter; }
        set { _pageCounter = value; }
    }

    private string _levels;

    public string Levels
    {
        get { return _levels; }
        set { _levels = value; }
    }

    public void SomeMethod() { }

    public void SomeMethodWithArgs(string arg1, int arg2,
        params string[] arg3) { }
}

Share/Save/Bookmark

Categories: C#, LINQ Tags: ,

Functional Type member resolution with C#

June 11th, 2009 Simon Segal 4 comments

An interesting problem cropped up today regarding reflection and how LINQ might make for a strongly typed solution. K. Scott Allen suggested a while back to use lambdas to remove the use of ‘magic’ strings in building Fetching Intentions used in NFetchSpec and it was suggested by my colleague Mark that a similar approach be used in resolving a types property name using strongly typed expressions. Given the following class:

public class Criteria
{
    private int _pageCounter;

    public int PageCounter
    {
        get { return _pageCounter; }
        set { _pageCounter = value; }
    }

    private string _levels;

    public string Levels
    {
        get { return _levels; }
        set { _levels = value; }
    }
}

I want to dynamically resolve any property name using an Expression such as:

Expression<Func<Criteria, string>> f = c => c.Levels;

After fumbling around for a while it occurred that functional programming was yet again the simplest way to approach this.

public class PropertyNameResolver<T>
{
    public static string Resolve<TPropertyType>
        (Expression<Func<T, TPropertyType>> expression)
    {
        Func<Expression<Func<T, TPropertyType>>, string>
            prop_name_function = l =>
            {
                int posDot = l.Body.ToString().LastIndexOf(“.”) + 1;
                return l.Body.ToString().Remove(0, posDot);
            };
        var property_name =
            typeof(T).GetProperty(prop_name_function(expression)).Name;
        return property_name;
    }
}

By supplying the expression and encapsulating the function that takes the expression as an argument, we get access to the body and parameters in the expression tree built by the original lambda and when be execute the outer function we can extrapolate the property name. Here’s an example of the usage:

var pc = PropertyNameResolver<Criteria>.Resolve<int>(c => c.PageCounter);
Console.WriteLine(pc);

Functional goodness in C#.

Share/Save/Bookmark

Categories: C#, LINQ Tags: ,

Entity Framework, Fluent Interfaces & Domain Specific Languages

May 24th, 2009 Simon Segal 2 comments

I have been giving some thought lately  to how we might go about writing a small internal DSL for reporting on and or editing data in database. Immediately I thought about how LINQ (a DSL in its own right) might play it’s part in this and since we are talking Data, then the Entity Framework came immediately into consideration. Why should we have a DSL for accessing Data? It’s a commonly held opinion that SQL is a DSL for that very purpose, albeit a very general purpose DSL and LINQ is certainly a DSL.

Let’s consider the workers of the Northwind Trading company as an example of some possible beneficiaries to such a Data Centric DSL modelled around a specific business. Of course workers at Northwind have MS Access and SQL Server GUI tools (often called Graphical DSL’s), to help design their queries.

query_designer

A snippet

So what would our Northwind language look like? Given that we set up from the start to consider an internal DSL, I have chosen to use C# to implement this “little language” (very little) and we will use a fluent interface to accommodate our design. A query might be expressed like this:

public void Do()
{
    var custs = NorthwindLang
        .Customers
        .WithOrdersShippedFrom(“Germany”)
        .That()
        .Are()
        .OlderInYearsBy(5);
}

The Language

public static class NorthwindLang
{
    public static Customer[] Customers;
    private static NorthwindEntities ctx = null;

    public static Customer[] WithOrdersShippedFrom(this Customer[] customers,
        string country)
    {
        ctx = new NorthwindEntities();
        var customers_and_orders =
           (ObjectQuery<Customer>)
           from c in ctx.Customers.Include(“Orders”)
           where c.Orders.Any(o => o.ShipCountry == country)
           select c;

        Console.WriteLine(customers_and_orders.ToTraceString());

        customers = customers_and_orders.ToArray();

        customers.ToList()
            .ForEach(c => c.Orders.ToList()
                .ForEach(o => {
                    if (o.ShipCountry != country)
                    {
                        ctx.Detach(o);
                    }}));

        return customers;
    }

    public static Customer[] That(this Customer[] customers)
    {
        return customers;
    }

    public static Customer[] Are(this Customer[] customers)
    {
        return customers;
    }

    public static Customer[] OlderInYearsBy(this Customer[] customers, int years)
    {
        var years_ago = DateTime.Now.AddYears(-years);

        var newOrds = new EntityCollection<Order>();

        var coolFunc =
            new Func<IEnumerable<Order>,
                EntityCollection<Order>>(o =>
            {
                newOrds = new EntityCollection<Order>();
                o.ToList().
                    ForEach(ord => { ctx.Detach(ord);
                        newOrds.Add(ord); });
                return newOrds;
            });

        var filtered_customers =
            from c in customers
                 let neworders =
                      (from o in c.Orders
                      where (o.ShippedDate.HasValue) &&
                            (o.ShippedDate.Value < years_ago)
                      select o)
                 select new Customer()
                 {
                     CustomerID = c.CustomerID,
                     CompanyName = c.CompanyName,
                     Orders = coolFunc(neworders)
                 };

        customers =
            filtered_customers
            .Distinct()
            .ToArray();

        return customers;
    }
}

Problematic

Something worth noting about the OlderInYearsBy() method is the projection taking place with the Orders property assignment for each new Customer entity projected in the queries select clause. You can see that we are “projecting” the orders that match the criteria into the customers Orders collection, however as they have already been fetched from the Database and are attached to an ObjectContext, we need to detach them so they can be referenced by a new Customer Entity that is being returned in the array of Customers produced by the function. Also, you may have observed that we are working with extensions to Customer arrays and not EntityCollection<T> where T is of type Customer, further to that, the code presented is filtering data selected from method calls higher up the call chain of the fluent interface and their is nothing stopping a user from composing a query that does not work with the assumptions present in the fluent interfaces design, and consequently the behaviour may not be as expected. Another issue with this approach is grammar and creating sentences that make little sense and don’t adhere to the DSL’s intended use or rules.

public void Do3()
{
    var custs = NorthwindLang
        .That()
        .OlderInYearsBy(15)
        .WithOrdersShippedFrom(“Italy”)
        .Are()
        .That()
        .OlderInYearsBy(15);
}

Where to from here?

I want to follow up with a post on how to achieve similar outcomes using a functional approach and building compound queries using lambda expression that have been joined together with the logical & and | operators. A perfect candidate for this requirement is (dare I say it) the specification pattern. What I hope to achieve with this more functional approach is to be able to compose sentences of intent that build our query so that it can be submitted as one single SQL query. The issue of grammar still remains a problem and I have considered previously that a graphical designer that sits in front of a fluent interface might offer a solution and offer some options with respect to constraining the use of the fluent interface. Consider a UI design surface built with the VSX DSL tools that sits on top of our NorthwindLang fluent interface. Anyway we shall see where this journey takes us!

One final thing

I don’t recommend using an ORM for reporting purposes. The scenario under which this idea was proposed (rather envisioned) was one where the database in question is a constantly renewed small set of data that is exported from an enterprise Document Management System and it’s purpose is to provide an offline view of partitioned data relevant to a consultants work for a given client. This precludes the requirements from having to deal with issues such as concurrency, given that each instance of this database is usually single user in the most literal sense.

Share/Save/Bookmark

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia