sensei
sensei

Reputation: 7562

Data from model to controller

I have this working in my controller, but I want to follow best practices and put my database logic in Model.

I want to put all database logic (select, update, delete, insert) to MODEL, therefore I create methods in my model.

My method for retrieving the data:

public IQueryable<ChatLogsNameViewModel> getChatLogWithName()
{
    using (var db = new ChatLogContext())
    {
        var list = (from b in db.ChatLogs
                    select new ChatLogsNameViewModel()
                    {
                        UserProfile = b.UserProfile,
                        Message = b.Message,
                        Time = b.Time
                    });

        return list;
    }
}

This is my modelView:

public class ChatLogsNameViewModel
{
    public UserProfile UserProfile { get; set; }
    public string Message { get; set; }
    public DateTime Time { get; set; }

}

I call my getChatLogWithName() method in my controller like this:

List<ChatLogsNameViewModel> items = null;
using (var dba = new ChatLogContext())
{
    items = dba.getChatLogWithName().ToList();
    return View(items);
}

Error I get is:

The operation cannot be completed because the DbContext has been disposed.

What is the proper way to do this? I just want to pass collection (all records from 2 tables via join) to controller.

Upvotes: 0

Views: 206

Answers (2)

zs2020
zs2020

Reputation: 54514

Lifetime - DbContext

The lifetime of the context begins when the instance is created and ends when the instance is either disposed or garbage-collected. Use using if you want all the resources that the context controls to be disposed at the end of the block. When you use using, the compiler automatically creates a try/finally block and calls dispose in the finally block.

The problem was when the inner using got disposed, it invalidated the DbContext. So you need to use .ToList() to save the query result in memory.

Suppose getChatLogWithName is defined in the class called Repo, you can change the controller logic to something like this:

var repo = new Repo();
var items = repo.getChatLogWithName().ToList();

Or move .ToList() to getChatLogWithName.

Btw, you should not use the nested DbContexts cope, in your controller, you don't have to wrap it using another DbContextscope.

Upvotes: 2

marteljn
marteljn

Reputation: 6516

To ensure that the DBContext is not getting referenced after disposal. How about returning a list so you dont have to call .ToList():

public List<ChatLogsNameViewModel> getChatLogWithName()
    {
        using (var db = new ChatLogContext())
        {
            var list = (from b in db.ChatLogs
                        select new ChatLogsNameViewModel()
                        {
                            UserProfile = b.UserProfile,
                            Message = b.Message,
                            Time = b.Time
                        });

            return list.ToList();
        }
    }

and

items = dba.getChatLogWithName();

Or

Since it appears that dba is the same as db, couldn't you change your code to use the dba instance which won't get disposed until the end of your using statement within your controller.

public IQueryable<ChatLogsNameViewModel> getChatLogWithName()
    {

            var list = (from b in this.ChatLogs
                        select new ChatLogsNameViewModel()
                        {
                            UserProfile = b.UserProfile,
                            Message = b.Message,
                            Time = b.Time
                        });

            return list;
    }

Upvotes: 2

Related Questions