Редактирование объекта сохраняется без моего одобрения с помощью NHibernate

#c# #.net #nhibernate

#c# #.net #nhibernate

Вопрос:

У меня есть этот тестовый код:

 int productId;
{
    var codersAtWork = productService.Create();
    codersAtWork.Title = "Coders At Work";
    codersAtWork.Price = new Price(200, 160, 0.25m, "SEK");

    codersAtWork.FieldBag.ReleaseDate = new DateTime(2009, 9, 1);
    productService.Save(codersAtWork);
    productId = codersAtWork.Id;
}

ReSetUp(); // Closes and opens a new session

{
    var codersAtWork = productService.GetById(productId);
    Assert.AreEqual(new DateTime(2009, 9, 1), codersAtWork.FieldBag.ReleaseDate);

    codersAtWork.FieldBag.ReleaseDate = "Tomorrow";
    Assert.Throws<InvalidFieldException>(() => { productService.Save(codersAtWork); });

    var cleanCode = productService.Create();
    cleanCode.Title = "Foo";
    cleanCode.Price = new Price(300, 240, 0.25m, "SEK");
    cleanCode.FieldBag.ReleaseDate = new DateTime(2009, 9, 1);
    productService.Save(cleanCode); // This save will also save my incorrect product.
}

ReSetUp(); // Closes and opens a new session

{
    var codersAtWork = productService.GetById(productId);
    Assert.AreEqual(new DateTime(2009, 9, 1), codersAtWork.FieldBag.ReleaseDate);
}
  

Я хочу, чтобы мой сервис проверял продукт, который я ему отправляю, и сохранял его только в том случае, если он действителен. Но проблема в том, что когда я сохраняю что-то еще, что является действительным в том же сеансе, или вызываю Flush в сеансе, это будет сохранено без моего контроля над тем, является ли это действительным. Последнее утверждение здесь завершится ошибкой. продукт.FieldBag.Дата выпуска будет «Завтра».

FieldBag является динамическим и сохраняется в базе данных в формате Json. Но проблема актуальна и для другой проверки.

Можно ли настроить NHibernate для сохранения только элементов, которые я явно вызвал .saveOrUpdate() на

Ответ №1:

Вы можете вызвать Session.Evict() , чтобы удалить объекты из сеанса. Тогда NHibernate проигнорирует изменения в этих объектах.

В качестве альтернативы вы можете получить / запросить их с помощью StatelessSession .

Ответ №2:

Возможно, вы захотите использовать обработчики событий для этого. Вы можете использовать PreInsertEventListener и PreUpdateEventListener. Проверьте правильность вашей проверки и верните true, если проверка не наложит вето на действие.

http://www.nhforge.org/doc/nh/en/index.html#objectstate-events

Ответ №3:

Хотя вы можете удалить объект с помощью Session.Evict() , я бы посоветовал взглянуть на ваш подход для проверки. Если я вас правильно понимаю, то ваш productService.Save метод выполняет проверку правильности переданного объекта. Вместо проверки того, что объект действителен с помощью какого-либо диспетчера служб, вы должны перенести эту проверку в сам объект и заставить объект убедиться, что он никогда не станет недействительным.

Например:

 class House
{
    public Room Bedroom { get; set; }
}

class HouseService
{
    public ValidateHouse(House aHouse)  //There is no guarantee that this method is ever called
    {
        if (aHouse.Bedroom == null)
        {
            throw new InvalidFieldException();
        }
    }
}
  

В приведенном выше примере вы не можете гарантировать, что ValidateHouse когда-либо вызывался, и поэтому не можете гарантировать, что у вас есть действительный дом для сохранения (или что-либо с ним делать).

Перенести проверку в объект:

 class House
{
    private Room theBedroom;
    public Room Bedroom 
    { 
        get
        {
            return theBedroom;
        }
        set
        {
            if(value == null)
            {
                throw new ArgumentNullException();
            }
            theBedroom = value;
        }
    }
}
  

В этом примере гарантируется, что значение Bedroom никогда не будет равно null. Если кто-то пытается присвоить значение null для спальни, то генерируется исключение, и объект никогда не изменяется. Поскольку объект не изменен, NHibernate не будет пытаться сохранить его. Кроме того, это должно принести пользу всему вашему приложению, поскольку вы будете знать, что ваши объекты всегда будут находиться в допустимом состоянии.

 house.Bedroom = null;
house.Bedroom.ToString(); //With option 1 this will throw a NullPointerException.

house.Bedroom = null;  //With option 2 this will throw an ArgumentNullException 
                       //but your house object will still be in a known valid state.
house.Bedroom.ToString();