tags:

views:

82

answers:

3

Forgive me if this has been asked already. I've only just started using LINQ. I have the following Expression:

public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
    return m => (new CustomerSummary()
    {
        ID = m.ID,
        CustomerName = m.CustomerName,
        LastSalesContact = // This is a Person entity, no idea how to create it
    });
}

I want to be able to populate LastSalesContact, which is a Person entity.

The details that I wish to populate come from m.LatestPerson, so how can I map over the fields from m.LatestPerson to LastSalesContact. I want the mapping to be re-useable, i.e. I do not want to do this:

LastSalesContact = new Person()
{
   // Etc
}

Can I use a static Expression, such as this:

public static Expression<Func<TblUser, User>> SelectToUser()
{
    return x => (new User()
    {
        // Populate
    });
 }

UPDATE:

This is what I need to do:

return m => (new CustomerSummary()
{
    ID = m.ID,
    CustomerName = m.CustomerName,
    LastSalesContact = new Person()
    {
       PersonId = m.LatestPerson.PersonId,
       PersonName = m.LatestPerson.PersonName,
       Company = new Company()
       {
           CompanyId = m.LatestPerson.Company.CompanyId,
           etc
       }
    }
});

But I will be re-using the Person() creation in about 10-15 different classes, so I don't want exactly the same code duplicated X amount of times. I'd probably also want to do the same for Company.

A: 

I don't think you'll be able to use a lambda expression to do this... you'll need to build up the expression tree by hand using the factory methods in Expression. It's unlikely to be pleasant, to be honest.

My generally preferred way of working out how to build up expression trees is to start with a simple example of what you want to do written as a lambda expression, and then decompile it. That should show you how the expression tree is built - although the C# compiler gets to use the metadata associated with properties more easily than we can (we have to use Type.GetProperty).

This is always assuming I've understood you correctly... it's quite possible that I haven't.

Jon Skeet
@Jon Skeet - My Twitter call for help worked then? Heh. I updated my question.
GenericTypeTea
@GenericTypeTea: Okay, it looks like I understood properly... and I'm pretty sure you *will* need to write code to build up the expression manually. Sorry to be the bearer of bad news :(
Jon Skeet
@Jon Skeet - No problem, nothing like getting thrown in at the deep end. Any chance of a little answer update to push me in the right direction?
GenericTypeTea
@GenericTypeTea: Sorry for not responding before. I'm afraid I haven't got time to try this at the moment. As I said, I'd start off by writing one example in C# and see what the compiler does with it.
Jon Skeet
@Jon Skeet - No problem. I'll have a go.
GenericTypeTea
+1  A: 

Can't you just use automapper for that?

public static Expression<Func<TblCustomer, CustomerSummary>> SelectToSummary()
{
    return m => Mapper.Map<TblCustomer, CustommerSummary>(m);
}

You'd have to do some bootstrapping, but then it's very reusable.

UPDATE:

I may not be getting something, but what it the purpose of this function? If you just want to map one or collection of Tbl object to other objects, why have the expression?

You could just have something like this:

var customers = _customerRepository.GetAll(); // returns IEnumerable<TblCustomer>
var summaries = Mapper.Map<IEnumerable<TblCustomer>, IEnumerable<CustomerSummary>>(customers);

Or is there something I missed?

Necros
@Necros - I should clarify, I'm using EntityFramework, so this will probably throw some method not supported error.
GenericTypeTea
@GenericTypeTea - why? I use automapper with EF all the time. Can you post an example of how are you going to use this method?
Necros
@Necros - Doesn't work: LINQ to Entities does not recognize the method 'Domain.Models.CustomerSummary Map[TblCustomer,CustomerSummary](Dal.Model.TblCustomer)' method, and this method cannot be translated into a store expression. I'm trying to use it in an EF Select.
GenericTypeTea
@GenericTypeTea see my update
Necros
Hmm.. I suppose I could return all the data I want and then map it. Basically, at the moment I'm trying to load all my domain objects from my DTO objects. I'm going to try this in the morning. So what I'll do is; Do all my filtering/paging in EF and then once I have my List of results, I'll map them as you've suggested. Thanks.
GenericTypeTea
A: 

How about this:

public static Person CreatePerson(TblPerson data)
{
    // ...
}

public static Expression<Func<TblPerson, Person>>  CreatePersonExpression()
{
    return d => CreatePerson(d);
}


return m => (new CustomerSummary()
{
    ID = m.ID,
    CustomerName = m.CustomerName,
    LastSalesContact = CreatePerson(m.LatestPerson)
});
ChaosPandion
I get the error 'The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.'.
GenericTypeTea
@Generic - Doh! I'll be back later for another attempt.
ChaosPandion
@Chaos - Thanks. You had me excited for a moment there.
GenericTypeTea
@Chaos - Person is not a valid method again....
GenericTypeTea