Search code examples
c#.netentity-frameworklinq-to-entities

Calling linq expression in other linq expression


My application contains several business layer types. I create them from Entity Framework entities using linq expressions. Below I put sample code that should describe my current solution. Please consider, that this is only simple example. My real business layer types are much more complex.

public class SimpleType
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }

    public static Expression<Func<simple_type_entity, SimpleType>> CreateExpression()
    {
        return arg => new SimpleType
        {
            Id = arg.id,
            Name = arg.name,
            Description = arg.desc
        }
    }
}
public class ComplexType
{
    public Guid Id { get; set; }
    public SimpleType Property1 { get; set; }
    public SimpleType Property2 { get; set; }

    public static Expression<Func<complex_type_entity, ComplexType>> CreateExpression()
    {
        return arg => new ComplexType
        {
            Id = arg.id,
            Property1 = new SimpleType 
            { 
                Id = arg.property1.id, 
                Name = arg.property1.name,   
                Description = arg.property1.desc
            },
            Property2 = new SimpleType { .... }
        }
    }
}

You can notice that ComplexType creates SimpleType many times and SimpleType creation code is duplicated. How can I call linq expression from another expression? I would like to use SimpleType.CreateExpression() in all places where SimpleType is created. I use linq expressions, because as I know, expressions are translated to sql queries, so new solution should be also translated to sql queries / compatible with linq to entieties.


Solution

  • This first version does not work when used on an IQueryable. (only on an IEnumerable) Scroll to the final version in this post to get the IQueryable-working version.

    public class ComplexType
    {
        public Guid Id { get; set; }
        public SimpleType Property1 { get; set; }
        public SimpleType Property2 { get; set; }
    
        public static Expression<Func<complex_type_entity, ComplexType>> CreateExpression()
        {
            var compiledSimpleTypeFnc = SimpleType.CreateExpression().Compile();
            return arg => new ComplexType
            {
                Id = arg.id,
                Property1 = compiledSimpleTypeFnc(arg.property1),
                Property2 = compiledSimpleTypeFnc(arg.property2)
            };
        }
    }
    

    or if you really want to keep it as an expression to the very end:

    public class ComplexType
    {
        public Guid Id { get; set; }
        public SimpleType Property1 { get; set; }
        public SimpleType Property2 { get; set; }
    
        public static Expression<Func<complex_type_entity, ComplexType>> CreateExpression()
        {
            var expr = SimpleType.CreateExpression();
            return arg => new ComplexType
            {
                Id = arg.id,
                Property1 = expr.Compile()(arg.property1),
                Property2 = expr.Compile()(arg.property2)
            };
        }
    }
    

    Edit: The below code works with entity framework.

    using System;
    using System.Linq.Expressions;
    using ConsoleApplication2;
    using System.Linq;
    
    class Program2
    {
        public static void Main(string[] args)
        {
            using (var db = new TestEntities())
            {
                var exp = db.complex_type_entity.Select(ComplexType.CreateExpression()).First();
            }
        }
    }
    
    public class SimpleType
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    
        public static Expression<Func<simple_type_entity, SimpleType>> CreateExpression()
        {
            var parameterExpr = Expression.Parameter(typeof(simple_type_entity), "p0");
            return Expression.Lambda<Func<simple_type_entity, SimpleType>>(CreateExpression(parameterExpr), parameterExpr);
        }
    
        public static MemberInitExpression CreateExpression(Expression sourceExpr)
        {
            return Expression.MemberInit(
                Expression.New(typeof(SimpleType)),
                Expression.Bind(typeof(SimpleType).GetProperty("Id"), Expression.Property(sourceExpr, "id")),
                Expression.Bind(typeof(SimpleType).GetProperty("Name"), Expression.Property(sourceExpr, "name")),
                Expression.Bind(typeof(SimpleType).GetProperty("Description"), Expression.Property(sourceExpr, "desc")));
        }
    }
    
    public class ComplexType
    {
        public Guid Id { get; set; }
        public SimpleType Property1 { get; set; }
        public SimpleType Property2 { get; set; }
    
        public static Expression<Func<complex_type_entity, ComplexType>> CreateExpression()
        {
            var parameterExp = Expression.Parameter(typeof(complex_type_entity), "p0");
    
            return Expression.Lambda<Func<complex_type_entity, ComplexType>>(
                Expression.MemberInit(
                    Expression.New(typeof(ComplexType)),
                    Expression.Bind(typeof(ComplexType).GetProperty("Id"), Expression.Property(parameterExp, "id")),
                    Expression.Bind(typeof(ComplexType).GetProperty("Property1"), SimpleType.CreateExpression(Expression.Property(parameterExp, "simple_type_entity"))),
                    Expression.Bind(typeof(ComplexType).GetProperty("Property2"), SimpleType.CreateExpression(Expression.Property(parameterExp, "simple_type_entity1")))),
            parameterExp);
        }
    }