16

This works in LINQ-to-SQL:

var customersTest = from c in db.Customers
                select new
                {
                    Id = c.Id,
                    Addresses = from a in db.Addresses where c.Id.ToString() == 
                        a.ReferenzId select a
                };

foreach (var item in customersTest)
{
    Console.WriteLine(item.Id);
}

But a similar example in Entity Framework gets an error message that says basically that it can't "translate it to SQL", here is the original error message in German:

"'LINQ to Entities' erkennt die Methode 'System.String ToString()' nicht, und diese Methode kann nicht in einen Speicherausdruck übersetzt werden."

Translation:

"'LINQ to Entities' does not recognize Method 'System.String ToString()', this method can not be translated into a memory expression.

Can anyone shed any light on how we could get this kind of statement to work in Entity Framework or explain why it gets this error?

Edward Tanguay
  • 189,012
  • 314
  • 712
  • 1,047
  • Is Id a string already? Not sure why that would cause the EF an issue but error message seems to point to that being the stumbling block. You'd thing string.ToString() would work pretty quickly :P – Daniel Elliott Dec 17 '09 at 10:31
  • Id is an integer in the L2S example. In our real EF example it is a GUID. Interestingly ToString() is in intellisense and it compiles but gets that runtime error. – Edward Tanguay Dec 17 '09 at 10:32
  • @Edward Tanguay: I've just seen your questione and added an answer, I hope it is still useful even after such a long time ... – Matt Jul 10 '13 at 15:56

4 Answers4

10

Updated answer:

If you followed the link I gave you at the beginning of my answer, this missing feature has meanwhile received 75 votes and is now (finally!) implemented by Microsoft in EF 6.1. To all who participated: Thank you for voting! Your voice was heard.

For example:

var query = from e in context.Employees where e.EmployeeID.ToString() == "1" select e;

will now be translated to:

DECLARE @p0 NVarChar(1000) = '1'
SELECT [t0].[EmployeeID], [t0].[LastName], [t0].[FirstName], [t0].[Title], 
    [t0].[TitleOfCourtesy], [t0].[BirthDate], [t0].[HireDate], [t0].[Address],[t0].[City],
    [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[HomePhone], [t0].[Extension], 
    [t0].[Photo], [t0].[Notes], [t0].[ReportsTo], [t0].[PhotoPath]
FROM [Employees] AS [t0]
WHERE (CONVERT(NVarChar,[t0].[EmployeeID])) = @p0

i.e. e.EmployeeID.ToString() translates to (CONVERT(NVarChar,[t0].[EmployeeID])).


Original answer:

It makes no sense to me why Linq2EF does not translate .ToString() into a proper SQL statement, as Linq2SQL does, only the Microsoft dev team knows the reason why they did not implement it yet. :-(

But you can raise the priority to implement it if you vote for this feature by following this link.

Luckily there are also 2 workarounds available, both of them I used recently in EF queries:


I) What helped me to get around this limitation was to change the query into a list, like so:

var customersList = (from c in db.Customers
             select c).ToList(); // converts to IEnumerable<T> ...
var customersTest = (from c in customersList 
             select new {Id=c.ID.ToString()}); // ... which allows to use .ToString()

The statement .ToList() converts to IEnumerable<T>, where .ToString() is available. Note that, Depending on the requirements, you can use .AsEnumerable() as well, which has the advantage that deferred execution is supported which is better if you have multiple linq queries depending on each other or if you're using different parameter values (many thanks to Divega for this hint!).

Afterwards you can use this query as you wish , e.g.:

var customersTest2 = from c in customersTest                 
    select new
            {
                Id = c.Id,
                Addresses = from a in db.Addresses where c.Id == a.ReferenzId select a
            };

Of course if you need you can add more properties to the objects of customersTest as required. You can also optimize the query above, I have only used 3 steps for readability of this example.


II) For simple conversions, and if you have to reuse the generated query in further subqueries (and it needs to remain IQueryable), use SqlFunctions from System.Data.Objects.SqlClient, they will be translated into SQL queries correctly.

Example 1: Date conversion (you have to use dateparts as below shown)

var customersTest = from c in db.Customers
    select new {
        strDate=SqlFunctions.DateName("dd", c.EndDate)
            +"."+SqlFunctions.DateName("mm", c.EndDate)
            +"."+SqlFunctions.DateName("yyyy", c.EndDate) 
    }

Example 2: Numeric to string conversion

var customersTest = from c in db.Customers
    select new {
        strID=SqlFunctions.StringConvert((double)c.ID)
    }

This should help you out of most situations where conversions into strings are required.


Matt
  • 25,467
  • 18
  • 120
  • 187
  • 1
    You can us AsEnnumerable() as well instead of ToList(). This may be a better option if you want to preserve deferred execution and the ability to execute the query multiple times with different parameter values. – divega Aug 28 '13 at 11:58
  • @divega: Thank you for the hint, I have tried it and it works well! I have also updated my answer. – Matt Aug 30 '13 at 08:01
  • **Another hint**: If you're using `SqlFunctions.StringConvert(...)`, then you'll need `.Trim()` in some cases to remove the spaces the conversion function creates. Surprisingly, you can use `SqlFunctions.StringConvert(...).Trim()` in a query! :-) – Matt May 26 '14 at 11:45
  • If you want to know, **how to upgrade**, I've found a nice article in the Visual Studio magazine: [How to upgrade and new features of EF 6](http://visualstudiomagazine.com/articles/2014/03/01/whats-new-in-entity-framework-6.aspx). This article is from 04/01/14, so it doesn't include all of the new features of EF 6.1, but it's a good start ... if someone knows an even better article, please let me know! – Matt Jul 11 '14 at 08:04
  • By the way, if you're looking for all SqlFunctions in .NET framework 4.5, [here](https://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions_methods(v=vs.110).aspx) is a link. You need to reference `System.Data.Entity.dll` and import the namespace `System.Data.Objects.SqlClient` as described. – Matt Mar 06 '15 at 11:36
  • I assume this [`DbContext.ToString()` method](https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext.tostring(v=vs.113).aspx) is not the one that was meant, or is it? – surfmuggle Oct 23 '16 at 09:32
  • I can't tell you how they solved it, but I assume it is a generic extension method they might have created (as it needs to apply to various types of objects). – Matt Oct 24 '16 at 14:24
  • @surfmuggle: I have now added an example how `.ToString()` is being translated into T-SQL. – Matt Dec 08 '16 at 09:21
9

Simply put: LINQ to Entities doesn't know about the conversion from your ID type to a string.

What is the type of c.ID? Is there any reason why it's one type for ID, but another for ReferenzId? If at all possible, make them the same type, at which point you won't have a problem any more. I don't know if there are other ways of performing conversions in LINQ to Entities - there may be - but aligning the types would be cleaner.

By the way, this really looks like it's a join:

var query = from c in db.Customers
            join a in db.Addresses on c.Id equals a.ReferenzId into addresses
            select new { Id = c.Id, Addresses = addresses };

EDIT: To respond to your comment - ToString appears in IntelliSense because the compiler has no real idea what your query is going to mean or how it will be translated. It's perfectly valid C#, and can generate a valid expression tree - it's just that EF doesn't know how to convert that expression tree into SQL.

You could try using Convert.ToString(c.Id) instead of just calling c.Id.ToString()...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • it's a historical database that we are using where a.ReferenzID is indeed a string, the reasons being that it can be joined to an int in one table but a GUID in another. – Edward Tanguay Dec 17 '09 at 10:39
  • Try converting the other way round? Call `new Guid(a.ReferenzId)` instead? – Jon Skeet Dec 17 '09 at 10:55
  • I doubt the parameterized constructor will work, but I'm thinking that `String.Equals` or `Guid.Equals` might. – Craig Stuntz Dec 17 '09 at 16:09
  • 2
    AFAIR the main reason ToString wasn't supported from the beginning is that we couldn't find a way to implement a canonical function that would perform conversion to string from all the possible different input types in all the relevant target database engines. It is anyway something we can revisit in the future. – divega Aug 28 '13 at 12:03
6

Entity Framework 6.1 RTM which was just released now support .ToString()

James Hancock
  • 3,348
  • 5
  • 34
  • 59
  • Yes, I noticed by coincidence that it supports it. But this is not mentioned in any reference. May you please provide a reference about this issue? – Ashraf Sabry Mar 31 '15 at 12:05
  • It's posted in the answer above http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/2327346-support-tostring-method-in-linq-to-entities – Ashraf Sabry Mar 31 '15 at 12:14
-2

LINQ to Entities as far as I understand it (for v1) is very primative. In otherwords it doesn't know how to take the extension method "ToString()" and generate the SQL for it.

In LINQ to SQL, it executes the extension method "ToString()" before generating the SQL. The difference is that LINQ to Entities uses IQueryable instead of IEnumerable.

BUT, from what I remember casting should work (because casting is a data type and SQL knows about CAST()).

So

c.Id.ToString() should really be (string)c.Id

(also, make sure it is (string) and not (String)).

One of the downfalls I would say about using Lambda (in Entity Framework) to generate the SQL expression instead of pure LINQ.

Keep in mind too, that using CAST on the left side of the equals sign in SQL is a bit ill performing :-)

jwendl
  • 942
  • 7
  • 13
  • sorry for the late DV: `(string)c.Id` would not compile with a "Cannot convert type 'int' to 'string'." – Marc L. Apr 17 '13 at 16:30
  • From what you wrote, one could think that Linq2SQL uses IEnumerable rather than IQueryable, which of course is NOT true. – Wiktor Zychla Jul 04 '13 at 07:51
  • 1
    @Wiktor Zychla: I've verified it, you can't simply cast into string in an EF query using `(string)` as cast operator. But have a look at my answer, I have two options now (posted [here](http://stackoverflow.com/a/17447930/1016343)) which are working fine for me. – Matt Jul 11 '13 at 07:23