4

So I am new to C#, LINQ, and MVC. I am trying to get a list of Ages, but it says

The specified type member 'Age' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

For a previous tutorial, they use this exact same logic, except they check a string, not an int (Age). Why is this giving me a fit, and how can I fix it?

public ActionResult SearchIndex(string ageValue, string searchString)
{
    if (!string.IsNullOrEmpty(ageValue))
    {
         var AgeList = new List<string>();
         var AgeListQry = from d in db.Actors orderby d.Age select d.Age.ToString();
         AgeList.AddRange(AgeListQry.Distinct());
    }
    // other stuff
}

I want to learn what is going on, so that I can avoid this in the future!

Entity Model code

public class Actor
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public DateTime BirthDate { get; set; }
        public int Age
        {
            get { 
                return (int)(DateTime.Now - BirthDate).TotalDays / 365; 
            }

        }
        public decimal NetValue { get; set; }
    }
    public class ActorDBContext : DbContext
    {
        public DbSet<Actor> Actors { get; set; }
    }
user2864740
  • 60,010
  • 15
  • 145
  • 220
Austin
  • 3,010
  • 23
  • 62
  • 97

3 Answers3

9

As mentioned in the comments, you can't call ToString() in a Linq to Entities query. Instead do it like this:

var AgeList = new List<string>();
//retrieve as whatever type Age is, no conversion in SQL Server
var AgeListQry = (from d in db.Actors orderby d.Age select d.Age).ToList();
//convert them after the fact, using Linq to Objects
AgeList.AddRange(AgeListQry.Select(a => a.ToString()).Distinct());

EDIT

I saw your latest update that does show that Age is not a database column. You are then required to do something like this (assuming BirthDate is properly mapped):

var AgeList = new List<string>();
//retrieve BirthDate from SQL Server and use ToList() to get it to run immediately
var AgeListQry = (from d in db.Actors orderby d.BirthDate select d.BirthDate).ToList();
//convert them after the fact, using Linq to Objects
AgeList.AddRange(AgeListQry.Select(bd => ((int)(DateTime.Now - bd).TotalDays / 365).ToString()).Distinct());

Linq to Entities maps your expressions to SQL statements and there is nothing for it to map to when you use your Age property. Instead, you need to get what you can from SQL Server (BirthDate) and then do the translation to Age yourself. You could replace the inline code with a method call like this if you'd rather:

AgeList.AddRange(AgeListQry.Select(bd => CalculateAge(bd)).Distinct());
//...
private string CalculateAge(DateTime birthday)
{
   return ((int)(DateTime.Now - bd).TotalDays / 365).ToString();
}
Sven Grosen
  • 5,616
  • 3
  • 30
  • 52
  • @BenAaronson thanks for catching that, added `ToList()` to the db query to ensure it is evaluated immediately – Sven Grosen May 14 '14 at 21:15
  • Yea on the last night (with .Distinct()) I am still getting the error message: The specified type member 'Age' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported. – Austin May 14 '14 at 21:17
  • @Austin is that with the `ToList()` or without it? – Sven Grosen May 14 '14 at 21:19
  • Without, let me copy/paste a second – Austin May 14 '14 at 21:21
  • The error appears again, but now it is being thrown at the .ToList() line...weird – Austin May 14 '14 at 21:22
  • Is your age column mapped to a database column? See http://stackoverflow.com/questions/11584660/the-specified-type-member-is-not-supported-in-linq-to-entities-only-initializer if not – Sven Grosen May 14 '14 at 21:24
  • I can now see that Age is not mapped as people have mentioned (I looked at the table), and I "think" I see what you are trying to do, I am just trying to wrap my head around it all as I still get compile exceptions. – Austin May 14 '14 at 21:39
  • @SvenGrosen Do I need to .ToString the AgeList.AddRange(AgeListQry.Select(bd => (int)(DateTime.Now - bd).TotalDays / 365).Distinct());? As List is a type? – Austin May 14 '14 at 21:49
  • @Austin Yes, you do, updating that now, sorry – Sven Grosen May 14 '14 at 21:55
  • @SvenGrosen No worries, I am beyond appreciative for your help. I think I will re-look at this tomorrow morning as my mind is fried and hopefully I will understand it better. Thank you! – Austin May 14 '14 at 21:56
  • @SvenGrosen That middle snippet worked like a charm! I shall look over it this morning to see what it is all doing. Now, for "proper" or "neat" programming does one way vs the other seem more professional in terms of having it all in SearchIndex, or having a private method for CalculateAge? (in terms of web-app development) – Austin May 15 '14 at 12:51
  • @Austin, that depends on a multitude of factors, the first one I would consider is whether you do this calculation in more than one place; if so, extract it into a method. – Sven Grosen May 15 '14 at 12:53
  • Okay thank you! I only have one last thing that confuses that but I am unsure if we can still continue a question in comments or not, its about how var actors = from a in db.Actors select a; is getting any of that information that was queried above. I think I am missing a link in where the data is being passed on, or being stored at.. – Austin May 15 '14 at 13:01
  • Not sure what you are asking, if it is truly bugging you, ask another question with more detail. – Sven Grosen May 15 '14 at 13:05
  • Okay I shall do that now as I truly want to understand everything I am learning. Thank you again very much! – Austin May 15 '14 at 13:07
1

You haven't the Age in you DB scheme and it is impossible to convert LINQ to DB query. You must order the Age collection in client side or add calculated column to your table.

Hamlet Hakobyan
  • 32,965
  • 6
  • 52
  • 68
  • I am sorry, but I do not understand what you mean? This is basically day two of me ever touching this stuff ever. haha – Austin May 14 '14 at 21:25
  • 1
    @Austin In basic terms: You have to remember, LINQ to Entities queries have to be directly translated into a plain SQL query. This is why you can't have .NET specific stuff (e.g. ToString() or ToList() etc) inside your query, because translator may not be able to directly convert your LINQ query to SQL query. – mnsr May 14 '14 at 21:38
  • Ohhh okay, that makes sense. I started learning visual studios, C#, SQL, LINQ, MVC, Code-First, (many other things) all these past few days so I still am learning all the basics. Thank you! – Austin May 14 '14 at 21:43
  • @Austin, If you able to change scheme of DB, the adding a calculated column to the table is the simplest way to solve this issue. – Hamlet Hakobyan May 14 '14 at 21:45
1

There is another way. Have a converter file, where you pass the object, works with the birthdate and produces the age, returns the same object. That also means, that you can't search the database for the age column

Iria
  • 433
  • 1
  • 8
  • 20