none
Only primitive types or enumeration types are supported in this context - entity framework RRS feed

  • Question

  • Hello,

    I am making a test blog application using enitity framework, and ran into this error:

    "Unable to create a constant value of type 'TestBlog.Models.Tag'. Only primitive types or enumeration types are supported in this context."

    I am using asp.net MVC with viewmodels passing data between my view and controller.

    In my controller of ActionResult Edit posts, I have this statement:

    return View("Form", new PostsForm
        {
    
            Tags = TestBlog.Tags.Select(tag => new TagCheckBox
            {
                Id = tag.Id,
                Name = tag.Name,
                IsChecked = post.Tags.Contains(tag)
            }).ToList() 
        });

    I have also tried this version:

    return View("Form", new PostsForm
        {
            Tags = (from item in TestBlog.Tags
                    select item).Select(tag => new TagCheckBox
                    {
                        Id = tag.Id,
                        Name = tag.Name,
                        IsChecked = post.Tags.Contains(tag)
                    }).ToList()
        });

    The issue seems to be caused by:

    IsChecked = post.Tags.Contains(tag)

    as I comment that statement, it no longer displays the error.

    The Error points to:

    Line 65:                 return View("Form", new PostsForm

    Here is my Tag.cs Model

    public class Tag
    {
        public Tag()
        {
            this.Posts = new HashSet<Post>();
        }
    
        public int Id { get; set; }
        public string Slug { get; set; }
        public string Name { get; set; }
    
        public virtual ICollection<Post> Posts { get; set; }
    }

    Here is my viewmodels:

    public class TagCheckBox
    {
        public int? Id { get; set;}
        public string Name { get; set; }
        public bool IsChecked { get; set;}
    }
    
    public class PostsForm
    {
        public bool IsNew { get; set; }
        public int? PostId { get; set; }
    
        [Required, MaxLength(128)]
        public string Title { get; set; }
    
        [Required, MaxLength(128)]
        public string Slug { get; set; }
    
        [Required, DataType(DataType.MultilineText)]
        public string Content { get; set; }
    
        public IList<TagCheckBox> Tags { get; set; }
    }

    Any advice is highly appreciated.

    Thank you






    • Edited by Zelkon Wednesday, May 21, 2014 3:42 AM
    • Moved by CoolDadTx Wednesday, May 21, 2014 2:00 PM EF related
    Wednesday, May 21, 2014 3:41 AM

Answers

  • I believe that you have encountered a limitation of Entity Framework. Your instruction TestBlog.Tags.Select takes as an argument a Lambda expression that expresses the shape of the data that you want to obtain. Entity Framework will take the Lambda expression and attempt to convert it into a SQL query that will obtain that kind of data from the database server. This mechanism is not all-powerful; there are things that you can express in C# but that Entity Framework doesn't know how to convert into SQL. That's why you get the error message "Unable to [whatever] in this context."

    One solution is to obtain simpler data in your query, for instance, just select the values of the fields. Then convert it into a List in memory by invoking .ToList() on the LINQ query. And then apply a second LINQ query onto that in-memory list to get your more "complex" selection. This second in-memory query will use Linq-to-objects instead of Linq-to-Entities, and it will support any code that is valid in C# (because doesn't have to be converted into SQL).

    Another alternative is to write manually your SQL Query and send it directly to the server (or save it in a View or Stored Procedure) instead of letting Entity Framework write it for you. This will be more efficient from the point of view of performance, but may be less clear and less maintainable from the point of view of your source code.

    • Marked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    Wednesday, May 21, 2014 10:30 AM
  • Hello Zelkon,

    I guess that Alberto means that you firstly use the .ToList to load data to memory and then use the LINQ2Object to query the data as:

    Order o = db.Orders.Include("OrderDetails").FirstOrDefault();
    
    var result = (from od in db.OrderDetails
    
    select od).ToList().Select(ood => new { OrderID = ood.OrderDetailID, IsCheck = o.OrderDetails.Contains(ood) });
    

    This will not throw the error.

    You can have a try.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    Tuesday, May 27, 2014 6:16 AM
    Moderator

All replies

  • I believe that you have encountered a limitation of Entity Framework. Your instruction TestBlog.Tags.Select takes as an argument a Lambda expression that expresses the shape of the data that you want to obtain. Entity Framework will take the Lambda expression and attempt to convert it into a SQL query that will obtain that kind of data from the database server. This mechanism is not all-powerful; there are things that you can express in C# but that Entity Framework doesn't know how to convert into SQL. That's why you get the error message "Unable to [whatever] in this context."

    One solution is to obtain simpler data in your query, for instance, just select the values of the fields. Then convert it into a List in memory by invoking .ToList() on the LINQ query. And then apply a second LINQ query onto that in-memory list to get your more "complex" selection. This second in-memory query will use Linq-to-objects instead of Linq-to-Entities, and it will support any code that is valid in C# (because doesn't have to be converted into SQL).

    Another alternative is to write manually your SQL Query and send it directly to the server (or save it in a View or Stored Procedure) instead of letting Entity Framework write it for you. This will be more efficient from the point of view of performance, but may be less clear and less maintainable from the point of view of your source code.

    • Marked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    Wednesday, May 21, 2014 10:30 AM
  • Thanks for your response.

    I am not too familiar with Linq, nor lambda expressions.  But is this something similar to you suggestion?:

    Tags = (from item in TestBlog.Tags
            select item).Select(tag => new
            {
                Id = tag.Id,
                Name = tag.Name,
                IsChecked = post.Tags.Any(t => t.Id == tag.Id)
            })
            .ToList()
            .Select(tag => new TagCheckBox
            {
                Id = tag.Id,
                Name = tag.Name,
                IsChecked = tag.IsChecked
            })
            .ToList()

    although, the code above still displays the same error

    Thanks again!

    • Marked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    • Unmarked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    Thursday, May 22, 2014 5:38 PM
  • Hello Zelkon,

    I guess that Alberto means that you firstly use the .ToList to load data to memory and then use the LINQ2Object to query the data as:

    Order o = db.Orders.Include("OrderDetails").FirstOrDefault();
    
    var result = (from od in db.OrderDetails
    
    select od).ToList().Select(ood => new { OrderID = ood.OrderDetailID, IsCheck = o.OrderDetails.Contains(ood) });
    

    This will not throw the error.

    You can have a try.

    Regards.


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    • Marked as answer by Zelkon Thursday, May 29, 2014 5:28 AM
    Tuesday, May 27, 2014 6:16 AM
    Moderator
  • Thanks for clarifying!  adding tolist() now works perfectly.

    Thursday, May 29, 2014 5:30 AM
  • Hello, I have exactly the same error.

    Can you show me how you solved it?

    Tuesday, March 22, 2016 10:23 PM
  • Hello, I have exactly the same error.

    Can you show me how you solved it?


    Why don't you show your code and explain what you are trying to do? 
    Wednesday, March 23, 2016 4:57 AM