【问题标题】:Fluent NHibernate PersistenceSpecification CheckListFluent NHibernate PersistenceSpecification CheckList
【发布时间】:2010-12-21 10:51:56
【问题描述】:

我目前正在从事一个使用 Fluent NHibernate 的大学项目。我正在研究如何为我们的实体和 Fluent 映射创建测试。

然而,我在试图弄清楚如何使用 PersistenceSpecification 的 CheckList 时遇到了死胡同。

单元测试失败并出现以下错误:

MvcShop.Core.Tests.EntitiesTests.ItemTest.CanMapItem threw exception:  NHibernate.PropertyValueException: not-null property references a null or transient valueMvcShop.Core.Entities.ItemPicture.Item.

测试定义为:

private IList<ItemPicture> _itemPictures = new List<ItemPicture>()
{
new ItemPicture { Filename = "test.jpg", Title = "Test title", PrimaryPicture = true},
        new ItemPicture { Filename = "test2.jpg", Title = "Test title 2" }
    };

    [TestMethod]
    public void CanMapItem()
    {
        new PersistenceSpecification<Item>(Session)
            .CheckProperty(i => i.Title, "Test item")
            .CheckProperty(i => i.Description, "Test description")
            .CheckProperty(i => i.SalesPrice, (decimal)0.0)
            .CheckList(i => i.ItemPictures, _itemPictures) // Complains that Item on ItemPicture is null.
            .VerifyTheMappings();
    }

我的映射定义为:

public ItemMap()
    {
        Table("Item");
        Id(i => i.ItemID).GeneratedBy.Identity().Column("Item_id");
        Map(i => i.ItemNo).Nullable().Length(30);
        Map(i => i.Title).Not.Nullable().Length(250);
        Map(i => i.Description).Nullable();
        Map(i => i.SalesPrice).Not.Nullable().Precision(18);
        Map(i => i.AverageRating).Precision(18).Nullable();
        Map(i => i.Visible).Not.Nullable();
        Map(i => i.Weight).Not.Nullable().Precision(18);
        Map(i => i.TimesPurchased);
        Map(i => i.InStock).Not.Nullable();
        Map(i => i.DateAdded).Not.Nullable();
        HasManyToMany(i => i.ItemCategories).Cascade.All().Inverse().Table("ItemCategoryItem");
        HasMany(i => i.ItemPictures).Cascade.AllDeleteOrphan().Inverse().LazyLoad();
        HasMany(i => i.Comments).Cascade.AllDeleteOrphan().Inverse().LazyLoad();
        HasMany(i => i.Ratings).Inverse().LazyLoad();
    }

public ItemPictureMap()
    {
        Table("ItemPicture");
        Id(i => i.ItemPictureID).GeneratedBy.Identity().Column("ItemPicture_id");
        Map(i => i.Title).Nullable();
        Map(i => i.Filename).Not.Nullable();
        Map(i => i.PrimaryPicture).Not.Nullable();
        References(i => i.Item).Not.Nullable().Column("Item_id");
    }

我真的不知道在使用 PersistenceSpecification 类时如何填充 ItemPicture 的 Item 属性。

有什么想法吗?

最好的问候, 丹麦肯尼​​斯

【问题讨论】:

  • 我也有同样的问题。我的映射工作正常,因为当我通常保存根对象时,关联的集合被正确保存。但是当我使用 CheckList 检查时,它似乎没有遵循级联。结果,在插入集合项时,会抛出空引用错误。

标签: c# fluent-nhibernate mstest fluent


【解决方案1】:

您不需要重写 GetHashCode 和 Equals 并创建自己的 IEqualityComparer。原因是默认情况下不能比较实体,而值对象可以。

默认情况下不能比较 DateTime 实例,原因很简单,它们不是一个值,它们是一个有值的实例,并且 datetime1 != datetime2 即使它们的日期完全相同,所以你需要做的是比较它们的关键值。对于像上面这样的课程。我认为 Item 包含一堆 ItemPictures,然后在您的 IEqualityComparer 实现中,当您覆盖 equals 时,您应该检查当前对象是否为 ItemPicture 类型,以及是否检查当前 ItemPicture 的 id 是否与另一方 ItemPicture.Id 匹配。代码胜于雄辩,我举个小例子:

[TestMethod]
public void CanMapItem()
{
    new PersistenceSpecification<Item>(Session, new CustomIEqualityComparer())
        .CheckProperty(i => i.Title, "Test item")
        .CheckProperty(i => i.Description, "Test description")
        .CheckProperty(i => i.SalesPrice, (decimal)0.0)
        .CheckList(i => i.ItemPictures, _itemPictures) // Complains that Item on ItemPicture is null.
        .VerifyTheMappings();
}


public class CustomIEqualityComparer: IEqualityComparer
{
    public bool Equals(object x, object y)
    {
        if (x == null || y == null)
        {
            return false;
        }
        if (x is ItemPicture && y is ItemPicture)
        {
            return ((ItemPicture) x).Id == ((ItemPicture) y).Id;
        }
        if(x is DateTime && y is DateTime)
        {
            return ((DateTime)x).Year ==((DateTime)y).Year;
        }
        return x.Equals(y);
    }

    public int GetHashCode(object obj)
    {
        throw new NotImplementedException();
    }
}

【讨论】:

  • 有道理,谢谢。但是,我不认为这是问题的原因。 IE。即使使用 CustomIEqualityComparer,它也不起作用。我仍然认为该错误是由于 ItemPicture 上的 Item 未填充并且映射说它不能为空。
【解决方案2】:

我认为在对它运行测试之前,ItemPicture 必须存在于数据库中(根据 Fluent 文档:https://github.com/FluentNHibernate/fluent-nhibernate/wiki/persistence-specification-testing - 请参阅该页面上的最后一行。)

试试:

[TestMethod]
public void CanMapItem()
{
    var p1 = new ItemPicture { Filename = "test.jpg", Title = "Test title", PrimaryPicture = true};
    var p2 =  new ItemPicture { Filename = "test2.jpg", Title = "Test title 2" };
    using (var tx = Session.BeginTransaction())
    {
        Session.Save(p1);
        Session.Save(p2);
    };
    new PersistenceSpecification<Item>(Session)
        .CheckProperty(i => i.Title, "Test item")
        .CheckProperty(i => i.Description, "Test description")
        .CheckProperty(i => i.SalesPrice, (decimal)0.0)
        .CheckList(i => i.ItemPictures, new List<ItemPicture> {p1, p2});
        .VerifyTheMappings();
}

【讨论】:

    【解决方案3】:

    CheckList 似乎有一个错误。尽管您的映射是正确的,但它会在保留父级之前尝试保留子级。 如果您改用 CheckComponentList,您的 Item 将在 ItemPictures 之前被持久化并且您的测试应该通过。

    【讨论】:

    • +1 表示CheckComponentList。但是,持久化相关实体的顺序是由映射本身决定的,不是测试的责任。
    猜你喜欢
    • 2010-11-29
    • 2011-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-10
    相关资源
    最近更新 更多