andrey.shedko
andrey.shedko

Reputation: 3238

Razor. @foreach statement cannot operate because does not contain public definition for GetEnumerator

As I know IQueryable same as IEnumerator both contains GetEnumerator method, but when I'm passing to partial view IQueryable object, Razor said that there is no definition for GetEnumerator. Here is interface definition:

 public interface IComments : IDisposable
    {
        IQueryable<comments> GetPostComments(int postid);
        //void Add(comments comment);
        //void Update(comments comment);
        //void Remove(int id);
    }

Here is repository:

 public class CommentsRepository: IComments, IDisposable
    {
        private blogaspnetEntities db;
        public CommentsRepository(blogaspnetEntities db)
        {
            this.db = db;
        }
        public IQueryable<comments> GetPostComments(int postid)
        {
            var all = from a in db.comments
                      orderby a.Posted descending
                      where a.PostID == postid
                      select a;
            return all;
        }
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    db.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

And finally is partial view:

@model BlogAspNetMVC.Models.comments

<div class="row">
    @foreach (var item in Model)
    {
        <div class="col-md-12">
            <div class="panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">@item.Author " сказал " @item.Posted ":"</h3>
                </div>
                <div class="panel-body">
                    @Html.Raw(HttpUtility.HtmlDecode(@item.Comment))
                </div>
            </div>
        </div>
    }
</div>

I'm really can't get what's wrong because as you can see all of this is IQuerybale. P.S. And here is the model:

public partial class comments
    {
        public int ID { get; set; }
        public string Comment { get; set; }
        public Nullable<int> Author { get; set; }
        public Nullable<System.DateTime> Posted { get; set; }
        public Nullable<int> PostID { get; set; }

        public virtual blog_post blog_post { get; set; }
    }

P.P.S. Parent ViewModel:

<div class="col-md-12">
        @Html.Partial("~/Views/comments/Details.cshtml", new BlogAspNetMVC.Models.comments())
    </div>

Upvotes: 2

Views: 7995

Answers (3)

Shadi
Shadi

Reputation: 2246

You need first to understand the difference between IEnumerable and IQueryable in terms of their behavior in memory.

IEnumerable is more memory and performance expensive, cause it loads everything to memory so you will be able to trace its values, this is not a good choice for performance.

IQueryable creates a query in the memory, that query points to your data but it does not have your data, nothing loaded to the memory, for this reason you cannot trace it unless you load some or all its query data to the memory.

You can get benefit from IQueryable in case you want to view you data into pages (like grids or list), all what you need to do is to select part of the data and upload it from the source (would be DB) to the memory using the IQueryable and some parameters, as following.

IQueryable<Comment> dataquery = _db.Comments;

int pagesize = 20; //20 items to be viewed on each page
int page = 1;
IList commentslist = dataquery.Skip((page - 1) * pagesize).Take(pagesize).ToList();
foreach(Comment cmt in commentslist)
{
    //Here you can trace comments items 
}

Upvotes: 1

John
John

Reputation: 6553

A few things that are confusing:

public interface IComments : IDisposable
{
    IQueryable<comments> GetPostComments(int postid);
    //void Add(comments comment);
    //void Update(comments comment);
    //void Remove(int id);
}

public partial class comments
{
    public int ID { get; set; }
    public string Comment { get; set; }
    public Nullable<int> Author { get; set; }
    public Nullable<System.DateTime> Posted { get; set; }
    public Nullable<int> PostID { get; set; }

    public virtual blog_post blog_post { get; set; }
}

For c# naming conventions you should really rename those to Comment (singular, uppercase) and BlogPost (uppercase and no underscore) and the interface to ICommentRepository or something similar since the CommentRepository is what implements it not comments

The @model you are using should be IEnumerable (or IQueryable) which is why you are getting the error.

@model IEnumerable<BlogAspNetMVC.Models.Comment>

GetEnumerator is a method on "Lists" of objects, such as IEnumerable which is why Razor is mad, you are telling it your model is a single entity (BlogAspNetMVC.Models.comments) (even if you are passing in an array from the view), so its type-safety checks are failing. Naming conventions help here since you have a single Comment not an array (comments)

Upvotes: 1

Venu
Venu

Reputation: 66

You seem to be missed to add Comments class model definition.

Try this...

@model IEnumerable<BlogAspNetMVC.Models.comments>

When the Model needs iteration, the comments class should implement IEnumerable/IQueryable interface, in this case it is not implemented. Or the partial view should get a IEnumerable/IQueryable object as model.

You have to pass a List to the partial view rendering (model binding) to solve the problem.

This is what i tried and it worked for me.

The Controller should pass the IQueriable object to the view

IQueryable<comments> commentsList = commentsRepository.GetPostComments(1);
        return View(commentsList);

In the parent view (which renders the partial view) should use the @model directive as,

@model IQueryable<WebApplication1.Models.comments>

I modified @model directive in the partial view as,

@model IQueryable<WebApplication1.Models.comments>

Try once and it should work.

Upvotes: 3

Related Questions