DbContext был удален
Я разработал веб-приложение с ASP.NET MVC 4 и SQL Server 2008, я создаю класс ContextManager, чтобы иметь только один контекст базы данных на всех страницах.
public static class ContextManager
{
public static HotelContext Current
{
get
{
var key = "Hotel_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as HotelContext;
if (context == null)
{
context = new HotelContext();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
Он работает должным образом на большинстве страниц, но на странице регистрации что-то идет не так, и мой контекст удален со следующей ошибкой:
Операция не может быть завершена, так как DbContext был удален.
public ActionResult Register ( RegisterModel model )
{
if ( ModelState.IsValid )
{
// Attempt to register the user
try
{
WebSecurity.CreateUserAndAccount( model.UserName, model.Password,
new
{
Email = model.Email,
IsActive = true,
Contact_Id = Contact.Unknown.Id
} );
//Add Contact for this User.
var contact = new Contact { Firstname = model.FirstName, LastName = model.Lastname };
_db.Contacts.Add( contact );
var user = _db.Users.First( u => u.Username == model.UserName );
user.Contact = contact;
_db.SaveChanges();
WebSecurity.Login( model.UserName, model.Password );
на линии _db.Contacts.Add( contact );
Я получил исключение.
Но без использования ContextManager путем изменения
HotelContext _db = ContextManager.Current;
в:
HotelContext _db = new HotelContext();
проблема была решена. Но мне нужно использовать свой собственный ContextManager. В чем проблема?
4 ответа
Ваш контекст был размещен где-то еще (не в коде, который вы показали), поэтому, в основном, когда вы получаете к нему доступ из своего Register
действие, оно бросает исключение.
На самом деле, вы не должны использовать статический синглтон для доступа к вашему контексту. Сделать экземпляр нового DbContext
экземпляр для каждого запроса. См. C# работа с Entity Framework на многопоточном сервере
В моем случае мой метод GetAll не вызывал метод ToList() после предложения where в лямбда-выражении. После использования ToList() моя проблема была решена.
Where(x => x.IsActive).ToList();
Вы, вероятно, 'ленивая загрузка' свойства навигации User
в вашем представлении регистрации. Убедитесь, что вы включили его с помощью Include
метод на вашем DbSet
перед отправкой на просмотр:
_db.Users.Include(u => u.PropertyToInclude);
Также делимся DbContext
s со статическим свойством может иметь неожиданные побочные эффекты.
Зачем переопределять Dispose(bool)?
public partial class HotelContext : DbContext
{
public bool IsDisposed { get; set; }
protected override void Dispose(bool disposing)
{
IsDisposed = true;
base.Dispose(disposing);
}
}
Затем проверьте IsDisposed
public static class ContextManager
{
public static HotelContext Current
{
get
{
var key = "Hotel_" + HttpContext.Current.GetHashCode().ToString("x")
+ Thread.CurrentContext.ContextID.ToString();
var context = HttpContext.Current.Items[key] as HotelContext;
if (context == null || context.IsDisposed)
{
context = new HotelContext();
HttpContext.Current.Items[key] = context;
}
return context;
}
}
}
Может быть, может быть вариант.
Раньше у меня была такая же проблема. Я решил это, как было сказано выше. Создайте новый экземпляр вашего контекста.
Попробуйте использовать это:
using (HotelContextProductStoreDB = new ProductStoreEntities())
{
//your code
}
Таким образом, каждый раз, когда вы будете использовать свой код, будет создаваться новый экземпляр, и ваш контекст не будет уничтожен.