views:

72

answers:

2

Is it possible to call a custom method in a lambda expression.?

//Address a : It's an Entity
public string AddressConstructor(Address a)
{
    return a.City + "," + a.Province;
}



var Test = _db.MyTableTest.Select( t => new ViewModel
                                   {
                                      MyID = t.ID,
                                      StringAddress = AddressConstructor(t.Addr)
                                   };
A: 

You should be able to accomplish this using LINQKit to inline your expression into the expression tree.

http://www.albahari.com/nutshell/linqkit.aspx

This will cause the concatanation you're attempting to be run on the SQL Server, not in memory (as described in the other answer). SQL Server of course knows how to concatanate strings, but if your AddressConstructor did something else that SQL Server doesn't understand, then this approach would not work and you would indeed need to perform your custom method in memory using the approach described in the other answer.

Essentially LINQKit will flatten the tree so it actually gets executed as:

    var Test = _db.MyTableTest.Select( t => new ViewModel
 {
      MyID = t.ID,
      StringAddress = t.Addr.City + "," + t.Addr.Province
 };

which EF should have no problem executing (and the concatenation should happen on the SQL Server).

JeffN825
I'll give a try and let you know. As you explain, I'm better to perform this task in the sql server side than my IIS Server.
Jean-Francois
@Jean-Francois, you will NEVER be able to create an instance of ViewModel on SQL Server, since it doesn't even know about this type... Such a statement just can't be translated to SQL
Thomas Levesque
That's correct...you won't be able to create an instance of your ViewModel on SQL Server. That's silly. However, I'm suggesting he can concatenate the string values on the SQL Server, whereas in your example, you're doing it in memory.
JeffN825
Ok now I understand the difference between performing an action on the SQL Server or in the memory. Both techniques here works great.
Jean-Francois
A HUGE limitation of the approach suggested by Thomas Levesque is that you will not be able to filter on StringAddress on the SQL Server side. You would need to return ALL MyTableTest and filter in memory in order to ever add a subsequent Where statement that uses the StringAddress. The approach I suggest would all you to add a .Where(x=>x.StringAddress.Contains("y")) and have that execute on the SQL Server, rather than return all rows and execute in memory.
JeffN825
+1  A: 

You need to call AsEnumerable so that the projection is executed locally:

var Test = _db.MyTableTest.AsEnumerable()
                          .Select( t => new ViewModel
                                   {
                                      MyID = t.ID,
                                      StringAddress = AddressConstructor(t.Addr)
                                   };

Otherwise, the Queryable.Select method is used instead of Enumerable.Select, which causes Entity Framework to try to translate the lambda expression to a SQL query (which of course is not possible in that case)

Thomas Levesque
this method works great, but I will try the others too
Jean-Francois