在未经NHibernate批准的情况下保存编辑实体

时间:2011-04-20 08:14:23

标签: 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时,它将保存,而我无法控制它是否有效。这里的最后一个断言将失败。 product.FieldBag.ReleaseDate将是“明天”。

FieldBag是动态的,并作为Json保存到数据库中。但问题也适用于其他验证。

可以将NHibernate配置为仅保存我在

上明确调用.SaveOrUpdate()的项目

3 个答案:

答案 0 :(得分:4)

您可以致电Session.Evict()从会话中删除实体。然后NHibernate将忽略对这些实体的更改。

或者,您可以使用StatelessSession来获取/查询它们。

答案 1 :(得分:1)

您可能希望使用事件处理程序来执行此操作。您可以使用PreInsertEventListener和PreUpdateEventListener。如果验证未能否决该操作,请检查您的验证并返回true。

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

答案 2 :(得分:0)

虽然您可以使用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分配给Bedroom,则抛出异常并且永远不会更改对象。由于对象没有被更改,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();