138

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?

VansFannel
  • 45,055
  • 107
  • 359
  • 626

7 Answers7

182

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).

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • 1
    Very good solution - Thanks! ... What about if I'd had to extend this solution by another nullable value? `.Select(c => new { c.Id, c.Flag, c.Foo?.Code })` does not work. – skyfrog Oct 12 '17 at 08:02
  • 2
    @skyfrog The operator `?.` is not supported in expression trees. But other than that, you can extend the anonymous type with as many values you want - just don;t forget to name them when needed :) e.g. `c => new { c.Id, c.Flag, Code = (int?)c.Foo.Code }` – Ivan Stoev Oct 12 '17 at 08:15
  • 1
    Great! Many thanks @Ivan for your reply. I was so close! ... but it is always easy to say while looking back ;-) – skyfrog Oct 13 '17 at 09:17
  • Great answer, can be used with EF-Entities.. e.g. dbCtx.MyEntity.Where().Select( .. to anon object...).etc... – joedotnot Apr 17 '19 at 11:31
91

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

Eric D. Johnson
  • 10,219
  • 9
  • 39
  • 46
Rafael Merlin
  • 2,517
  • 1
  • 25
  • 31
16

Try this:

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

Been informed this isn't accepting in LINQ to entities.

Another option would be to pull the result into memory before selecting. If you are going to do this I would recommend doing all of the filtering before the .AsEnumerable() as it means you are only pulling back results that you want as opposed to pulling back the whole table and then filtering.

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

as well Tuple.Create(c.Id, c.Flag) could be changed to new Tuple(c.Id, c.Flag) if you want to make the code a bit more explicit in the tuples types

Dhunt
  • 1,584
  • 9
  • 22
11

In linq to entities you can project onto an anonymous type or onto a DTO.To avoid that issue you can use AsEnumerable extension method:

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

This method lets you work with Linq to Object instead Linq to Entities, so after call it,you can project the result of your query in whatever you need.The advantage of using AsEnumerable instead ToList is that AsEnumerable does not execute the query, it preserves deferred execution. It's good idea always filter your data first before call one of these methods.

Community
  • 1
  • 1
ocuenca
  • 38,548
  • 11
  • 89
  • 102
  • -1 This does not do the same thing as was asked by the OP. Sometimes, being able to create Tuples in a query, for Joining purposes is important. – Aron Jan 05 '21 at 06:51
1

Use this method to do this and use the async.

var codes = await codesRepo.SearchFor(predicate)
                    .Select(s => new
                    {
                        Id = s.Id,
                        Flag = s.Flag
                    }).FirstOrDefaultAsync();

                var return_Value = new Tuple<string, byte>(codes.Id, codes.Flag);
MohammadSoori
  • 2,120
  • 1
  • 15
  • 17
0

Just my two cents: this has caught me out a few times with the type names:

A few noddy examples:

    private Tuple<string, byte> v1()
    {
        return new Tuple<string, byte>("", 1);
    }

    private (string, int) v2()
    {
        return ("", 1);
    }

    private (string Id, byte Flag) v3()
    {
        return ("", 1);
    }

Regards.

IbrarMumtaz
  • 4,235
  • 7
  • 44
  • 63
  • The syntax you posted does not work. What you probably meant to write is `public (string Id, byte Flag) SearchFor(Expression predicate)`, but this is beside the point. Two cents shouldn't be an answer, but a comment. – M.Stramm Jan 15 '19 at 18:51
  • 2
    I updated my answer - i should have checked it before posting. I disagree; all info is useful to all visitors who land on this page regardless how it is posited. Comments do not convey intent as well as answer thanks to answers. – IbrarMumtaz Jan 16 '19 at 10:36
  • I do agree that added content is good and comments don't cater well to code examples. Thanks for editing, now it is clear that this is not an answer to the OP's question (but may help with tuple related problems). – M.Stramm Jan 28 '19 at 19:58
-1

You also can use record.

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/records

private record Code(string Id, byte Flag);

then use it like

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

later you can use a named property instead of a .Item1, .Item2

var code = codes.First();
...code.Id; 
...code.Flag;
Jaider
  • 14,268
  • 5
  • 75
  • 82
  • That defeats the purpose of creating a Tuple: not having to define a named structure. Also, tuples do have named members since a couple of years. – Gert Arnold May 14 '23 at 07:46
  • @gert-arnold-is-on-strike Named tuples is not supported on linq-sql. so you have to do a select with anonymous to read, materialize (asEnumerable, toList, etc), and then another select for named tuples... which it is cumbersome. In Linq-SQL, I tends to use a lot of anonymous type, or some classes or records, but I try to avoid tuples for the reason above. – Jaider Jun 12 '23 at 18:28
  • Sure, it's awkward, but it's a way to return fixed-format typed data from a method w/o having to define a class/struct etc. I think that's OP's purpose. – Gert Arnold Jun 12 '23 at 18:34