2015-06-15 35 views
1

Я хочу обновить M: N данных, но когда я делаю, что у меня есть это исключение:обновление M: N данных с помощью сеанса NHibernate .Net MVC

Инициализация [DataAccess.Model.Product # 6] - незаконно пытались связать прокси-сервер с двумя открытыми Sessions

Я думаю, что это что-то с моей Sesion кода, но не могу понять это вы можете мне помочь?

Вот код обновления сессии

public void Update(T entity) 
{ 
    using (ITransaction transaction = Session.BeginTransaction()) 
    { 
     Session.Update(entity); 
     transaction.Commit(); 
    } 
} 

Это как метод выглядит как контроллер

[HttpPost] 
public ActionResult Add(int product) 
{ 
    Create(); 

    Product productD = new ProductDao().GetById(product); 

    ProductsOfBag productsOfBag = new ProductsOfBag(); 

    User user = new UserDao().GetByLogin(User.Identity.Name); 
    Bag bag = new BagDao().GetByUser(user); 

    bag.Price += productD.Price; 
    bag.PriceDph += productD.PriceDph; 
    bag.NumberOfItems++; 

    ProductsOfBagDao productsOfBagDao = new ProductsOfBagDao(); 

    productsOfBag.IdBag = bag; 
    productsOfBag.IdProduct = productD; 

    productsOfBagDao.Create(productsOfBag); 

    IList<ProductsOfBag> products = productsOfBagDao.GetByBag(bag); 

    productD.Bags = products; 

    bag.Products = products; 

    BagDao bagDao = new BagDao(); 
    bagDao.Update(bag); 

    return RedirectToAction("Index", "Home"); 
} 

Product.hbm.xml

<class name="Product" table="Products" lazy="true"> 
    <id name="Id" column="id_product"> 
     <generator class="native" /> 
    </id> 
    <property name="Name" column="name" /> 
    <property name="PriceDph" column="priceDph" /> 
    <property name="Price" column="price" /> 
    <property name="ProductState" column="productState" /> 
    <property name="Maker" column="maker" /> 
    <property name="Description" column="description" /> 
    <property name="ProductWaranty" column="productWaranty" /> 
    <property name="Points" column="points" /> 
    <many-to-one name="Category" column="id_category" foreign-key="id_category" /> 
    <property name="ImageName" column="imageName" /> 
    <bag name="Bags" lazy="true" 
     inverse="true" batch-size="25" cascade="all-delete-orphan"> 
     <key column="id_product" /> 
     <one-to-many class="ProductsOfBag" /> 
    </bag> 
</class> 

Bag.hbm.xml

<class name="Bag" table="Bags" lazy="true"> 
    <id name="Id" column="id_bag"> 
     <generator class="native" /> 
    </id> 
    <property name="Price" column="price" /> 
    <property name="PriceDph" column="priceDph" /> 
    <property name="NumberOfItems" column="numberOfItems" /> 
    <many-to-one name="IdUser" column="id_User" foreign-key="id_User" /> 
    <bag name="Products" lazy="true" 
     inverse="true" batch-size="25" cascade="all-delete-orphan"> 
     <key column="id_bag" /> 
     <one-to-many class="ProductsOfBag" /> 
    </bag> 
</class> 

Product.cs

public class Product : IEntity 
{ 
    public virtual int Id { get; set; } 

    [Required(ErrorMessage = "Název produktu je vyžadován")] 
    public virtual string Name { get; set; } 

    private double _priceDph; 

    public virtual double PriceDph 
    { 
     get 
     { 
      _priceDph = Price + Price*0.21; 

      return _priceDph; 
     } 
     set { _priceDph = value; } 
    } 

    [Required(ErrorMessage = "Cena je vyžadována")] 
    [Range(0, 9000000, ErrorMessage = "Cena nemůže být záporná")] 
    public virtual int Price { get; set; } 
    public virtual string ProductState { get; set; } 

    [Required(ErrorMessage = "Výrobce je vyžadován")] 
    public virtual string Maker { get; set; } 

    [AllowHtml] 
    public virtual string Description { get; set; } 

    [Required(ErrorMessage = "Záruka je vyžadována")] 
    public virtual int ProductWaranty { get; set; } 

    [Required(ErrorMessage = "Počet bodů je vyžadován")] 

    private int _points; 

    public virtual int Points 
    { 
     get 
     { 
      _points = (int)PriceDph/10; 

      return _points; 
     } 
     set { _points = value; } 
    } 

    public virtual ProductCategory Category { get; set; } 

    public virtual string ImageName { get; set; } 

    public virtual IList<ProductsOfBag> Bags { get; set; } 
} 

Bag.cs ​​

public class Bag :IEntity 
{ 
    public virtual int Id { get; set; } 

    public virtual double Price { get; set; } 

    public virtual double PriceDph { get; set; } 

    public virtual int NumberOfItems { get; set; } 

    public virtual User IdUser { get; set; } 

    public virtual IList<ProductsOfBag> Products { get; set; }  
} 

NHibernateHelper.cs

public class NHibernateHelper 
{ 
    private static ISessionFactory _factory; 

    public static ISession Session 
    { 
     get 
     { 
      if (_factory == null) 
      { 
       var cfg = new Configuration(); 
       _factory = 
        cfg.Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Hibernate.cfg.xml")) 
         .BuildSessionFactory(); 
      } 
      return _factory.OpenSession(); 
     } 
    } 
} 

ответ

1

Существует проблема связана с отображением подобной коллекции против его другой экземпляр (ы) выполнения. Лучше, чтобы обсудить, что над кодом, так что это одна сущность

public class Bag :IEntity 
{ 
    ... 
    public virtual IList<ProductsOfBag> Products { get; set; }  
} 

И это второй один:

public class Product : IEntity 
{ 
    ...  
    public virtual IList<ProductsOfBag> Bags { get; set; } 
} 

И, кажется, из одного и того же типа: IList<ProductsOfBag>, но они фактически два разных экземпляров. Это означает, что этот кусок кода

Product productD = ...; 
Bag bag = ...; 

... 

ProductsOfBagDao productsOfBagDao = new ProductsOfBagDao(); 

productsOfBag.IdBag = bag; 
productsOfBag.IdProduct = productD; 

productsOfBagDao.Create(productsOfBag); 

нормально, но следующие строки являются реальной проблемой, источник, за исключением

// wrong lines 
IList<ProductsOfBag> products = productsOfBagDao.GetByBag(bag); 

// this is illegal 
productD.Bags = products; 
bag.Products = products; 

Это не допускается. У каждого объекта есть его собственная коллекция.Эти коллекции входят в состав NHibernate ISessionbag.Products) - они/экземпляры были созданы во время загрузки.

Таким образом, мы должны быть в состоянии Skipp, удалить эти 3 строку и просто позвонить:

BagDao bagDao = new BagDao(); 

// this will instruct NHibernate to use cascade 
bag.Products.Add(productsOfBag); 
bagDao.Update(bag); 

Если все объекты DAO один и тот же экземпляр ISession (см ниже), он должен теперь работать

ORIGINAL часть

Кроме того, когда мы используем NHibernate с веб-приложениями, в основном ASP.NET MVC или Web API, мы должны думать о единице работы, связанные с целой веб-запроса 0.

Для поддержки этого подхода мы можем использовать встроенные фильтры AOP или обработчики делегирования. Мы можем следовать этой всеобъемлющей пост:

NHibernate session management in ASP.NET Web API

в основном часть:

Session действия управления фильтра

(показывая упрощенный код сниппета)

// the AOP filter, MVC built in feature 
public class NhSessionManagementAttribute : ActionFilterAttribute 
{ 
    ... // some init stuff 

    // here we start session 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var session = SessionFactory.OpenSession(); 
     CurrentSessionContext.Bind(session); 
     session.BeginTransaction(); 
    } 

    // here we close it 
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) 
    { 
     var session = SessionFactory.GetCurrentSession(); 
     var transaction = session.Transaction; 
     if (transaction != null && transaction.IsActive) 
     { 
      transaction.Commit(); 
     } 
     session = CurrentSessionContext.Unbind(SessionFactory); 
     session.Close(); 
    } 

Некоторые аналогичные вещи :

В случае, что это не проблема, сессия уже открыт через веб-запроса в целом, мы получили бы исключение

... Незаконно попытался связать прокси с двумя открытыми сеансами ...

в случае, если мы сохранили в памяти один объект во время двух (или даже более) сеансов. И это легко (случайно) достичь с помощью функции ASP.NET MVC:

return RedirectTo... 

Мы могли бы быть с экземпляром загруженной Сущности ... загружаются в/вебе-запросе POST-то действия ... передается/перенаправлены к другому действию. Но это эффективно создаст новый веб-запрос. И это вызовет фильтры AOP ... которые закроют первый сеанс и откроют новый для нового запроса.

Чтобы избежать этого, мы должны сильно отличающие действия для

  • WRITE и
  • READ

Они не должны ничего делить. Сначала нужно сделать все ОБНОВЛЕНИЯ, ВСТАВКИ и УДАЛИТЬ - совершить транзакцию ... закрыть сеанс. Для перенаправления следует использовать только ID.Позже мы должны, в совершенно новой сессии, просто ПРОЧИТАТЬ - правильно совершенные и очищенные вещи ...

+0

Я новичок в asp.net, так что, пожалуйста, напишите мне это так :) Проблема в том, что Когда я поставлю первый продукт в сумку, он пройдет. Однако, когда я ставлю туда другое, у меня есть это исключение. Что вы посоветуете мне делать? – MrLucker518

+0

Если есть кто-то, кто хочет научиться NHibernate ... я с удовольствием помогу;) Не могли бы вы показать мне свое последнее картографирование? можете ли вы предоставить сущности и сопоставления hbm.xml? потому что, если он работает для одного ... мы сделаем его работающим для большего;) –

+0

Я использовал ваш код сущности и сопоставление, чтобы проверить, что должно быть неправильно ... Надеюсь, мой расширенный ответ поможет –

Смежные вопросы