开发者

Fluent NHibernate PersistenceSpecification CheckList

开发者 https://www.devze.com 2022-12-12 23:53 出处:网络
I am currently working on a college project in which we are using Fluent NHibernate. I am working on figuring how to create testing for our entities and Fluent mappings.

I am currently working on a college project in which we are using Fluent NHibernate. I am working on figuring how to create testing for our entities and Fluent mappings.

I have, however, hit a dead end while trying to figure how to use the CheckList of PersistenceSpecification.

The unit test fails with the following error:

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

The test is defined as:

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();
    }

My mappings are defined as:

public ItemMap()
    {
        Table("Item");
        Id(i => i.ItemID).GeneratedBy.Identity().Column("Item_id");
        Map(i => i.ItemNo).Nullable().Length(30);
        Map(i =&开发者_如何学Gogt; 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");
    }

I really can't figure how I can populate the Item property of ItemPicture when using the PersistenceSpecification class.

Any ideas?

Best Regards, Kenneth, Denmark


I think the ItemPicture has to exist in the DB before you run the test against it (as per the Fluent documentation: https://github.com/FluentNHibernate/fluent-nhibernate/wiki/persistence-specification-testing - see the last line on that page.)

Try:

[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();
}


CheckList seems to have a bug. It will try to persist the children before persisting the parent although your mappings are correct. If you use CheckComponentList instead, your Item will be persitsted before the ItemPictures and your test should pass.


You can't you need to override GetHashCode and Equals and create your own IEqualityComparer. The reason for this is that entities can't be compared by default whilst value object can.

DateTime for instance cannot be compared by default for the simple reason that they are not a value they are an instance with a value and there for datetime1 != datetime2 even if their dates are exactly the same so what you need to do is compare them on key values. For a class like above. I suppose that Item contains a bunch of ItemPictures and then in your IEqualityComparer implementation when you override equals you should check if the current object is of type ItemPicture and if it is check if the current ItemPicture's id match the other sides ItemPicture.Id. Since code speaks louder than words I'll give you a small example:

[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();
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消