rraszewski
rraszewski

Reputation: 1145

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.

Upvotes: 0

Views: 257

Answers (2)

Jaider
Jaider

Reputation: 14944

I created this Repository https://github.com/jaider/Entity-Expressions that contains @TimEeckhaut EF solution, but a little more reusable/generic library.

Here the database query:

var complexModels = context.ComplexEntities
                .Select(EntityExpressionHelper.CreateLambda<ComplexEntity, ComplexModel>())
                .ToList();

Here the model looks like:

public class ComplexModel
{
    [EntityExpression(nameof(ComplexEntity.Id))]
    public Guid Id { get; set; }

    [EntityExpression(nameof(ComplexEntity.Property1), IsComplex = true)]
    public SimpleModel Property1 { get; set; }

    [EntityExpression(nameof(ComplexEntity.Property2), IsComplex = true)]
    public SimpleModel Property2 { get; set; }
}

Upvotes: 1

John
John

Reputation: 3702

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);
    }
}

Upvotes: 2

Related Questions