Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Tuple in a Linq Select

I'm working with C# and .NET Framework 4.5.1 retrieving data from a SQL Server database with Entity Framework 6.1.3.

I have this:

codes = codesRepo.SearchFor(predicate)       .Select(c => new Tuple<string, byte>(c.Id, c.Flag))       .ToList(); 

And when I run it, I get this message:

Only parameterless constructors and initializers are supported in LINQ to Entities.

I don't know how I have to create the Tuple because all the examples that I have found are mostly like this one.

I have tried this:

codes = codesRepo.SearchFor(predicate)       .Select(c => Tuple.Create(c.Id, c.Flag))       .ToList(); 

And get this error:

LINQ to Entities does not recognize the method 'System.Tuple`2[System.String,System.Byte] Create[String,Byte](System.String, Byte)' method, and this method cannot be translated into a store expression.

Where is the problem?

like image 999
VansFannel Avatar asked Nov 05 '15 13:11

VansFannel


People also ask

What is tuple in LINQ?

The Tuple<T> class was introduced in . NET Framework 4.0. A tuple is a data structure that contains a sequence of elements of different data types.

How does select work in LINQ?

LINQ Select operator is used to return an IEnumerable collection of items, including the data performed on the transformation of the method. By using Select Operator, we can shape the data as per our needs. In it, we can use two syntax types; let's see each method working flow.

What does LINQ Select Return?

By default, LINQ queries return a list of objects as an anonymous type. You can also specify that a query return a list of a specific type by using the Select clause.

Is LINQ select slow?

Let's start off by acknowledging that using the LINQ operators (such as Select and Where ) does typically result in very slighly slower code than if you wrote a for or foreach loop to do the same thing. This is acknowledged in the Microsoft documentation: LINQ syntax is typically less efficient than a foreach loop.


2 Answers

While the answer by octavioccl works, it's better to first project the query result into anonymous type, and then switch to enumerable and convert it to tuple. This way your query will retrieve from the data base only the fields needed.

codes = codesRepo.SearchFor(predicate)     .Select(c => new { c.Id, c.Flag })     .AsEnumerable()     .Select(c => new Tuple<string, byte>(c.Id, c.Flag))     .ToList(); 

Note: The above rule applies to EF6. EF Core naturally supports tuples (in projection or as join/group keys) via tuple constructor, e.g. the original query simply works

codes = codesRepo.SearchFor(predicate)   .Select(c => new Tuple<string, byte>(c.Id, c.Flag))   .ToList(); 

but not the Tuple.Create method (EF Core 2.x).

like image 72
Ivan Stoev Avatar answered Sep 28 '22 09:09

Ivan Stoev


Just an updated answer for C# 7, now you can use a simpler syntax to create ValueTuples.

codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) .AsEnumerable() .Select(c => (c.Id, c.Flag)) .ToList(); 

You can even name the properties of the tuple now:

codes = codesRepo.SearchFor(predicate) .Select(c => new { c.Id, c.Flag }) // anonymous type .AsEnumerable() .Select(c => (Id: c.Id, Flag: c.Flag)) // ValueTuple .ToList(); 

So instead of using it as Item1 or Item2 you can access it as Id or Flag.

More docs on choosing-between-anonymous-and-tuple

like image 41
Rafael Merlin Avatar answered Sep 28 '22 10:09

Rafael Merlin