在FluentNHibernate中映射一对一,NHibernate尝试在父级之前编写子级

时间:2012-03-13 16:50:57

标签: nhibernate fluent-nhibernate

我正试图在FN中建立1:1的关系,但这有点痛苦。

我看了http://avinashsing.sunkur.com/2011/09/29/how-to-do-a-one-to-one-mapping-in-fluent-nhibernate/这似乎证实这应该有用但是嘿嘿,它一直试图在父表之前将记录插入子表中,这意味着子插入不包含必需的CustomerId外键约束。

   +-----------------------+      +----------------------+
   | tblCustomer           |      |  tblCustomerPhoto    |
   |-----------------------|      |----------------------|
   |                       | 1:1  |                      |
   | CustomerID (PK)       |+---->|  CustomerID (FK)     |
   | OtherJunk...          |      |  Photo (Image)       |
   |                       |      |                      |
   |                       |      |                      |
   +-----------------------+      +----------------------+

模型

public class Customer 
{
    public virtual int CustomerID { get; private set; }
    /* public virtual Other stuff */
}

public class CustomerPhoto
{
    public virtual int CustomerID { get;set;}
    public virtual Byte[] Photograph { get; set; }
}

地图

public class CustomerPhotoMap : ClassMap<CustomerPhoto>
{
    public CustomerPhotoMap()
    {
        Id(x => x.CustomerID)
            .Column("CustomerID")
            .GeneratedBy.Assigned();

        Map(x => x.Photograph)
            .CustomSqlType("Image")
            .CustomType<Byte[]>()
            .Nullable();
    }
}

public class CustomerMap : ClassMap<Customer>
{
    public CustomerMap()
    {

        Id(x => x.CustomerID)
            .GeneratedBy.Identity()
            .Column("CustomerID");
        HasOne<CustomerPhoto>(x => x.CustomerPhoto)
            .LazyLoad()
            .ForeignKey("CustomerID");
    }
}

测试

class CustomerMappingFixture : IntegrationTestBase
{
    [Test]
    public void CanMapCustomer()
    {
        new PersistenceSpecification<Customer>(Session)
            .CheckReference(x => x.CustomerPhoto, new CustomerPhoto(){ Photograph = Arrange.GetBitmapData(ImageFormat.Jpeg) })
            .VerifyTheMappings();
    }
}

现在,CustomerPhoto上的外键列设置为非空,我在CustomerPhotoMapping的表示法中重复此操作。 在(https://stackoverflow.com/a/2286491/529120)的基础上,我将其更改为可为空,并从映射中删除了符号。

无论如何,NHibernate都会回归 System.NullReferenceException:未将对象引用设置为对象的实例。

并且似乎首先尝试插入CustomerPhoto记录,将Customer作为CustomerId传递零;然后创建客户记录,然后尝试使用左外连接选择客户和照片。这显然不会起作用,因为它没有尝试更新照片表中的ID。

1 个答案:

答案 0 :(得分:2)

我注意到的一些事情

  1. 使用CheckReference验证此映射可能不正确。我很确定这只适用于多对一的关系。因此,它试图在CustomerPhoto之前插入Customer是有意义的。我会在这里用直接的NH会话写一个测试。我觉得使用PersistenceSpecification对我的许多非平凡的映射来说比使用它更麻烦。
  2. 一对一的映射看起来有点不对(下面提出的解决方案)
  3. 将图像列映射到字节数组时,我认为不需要声明自定义类型。下面的映射对我来说很好。我认为你对该属性映射的其他内容是不需要的。
  4. 我的映射几乎与你的映射相同,这就是我使用的:

    public class Customer 
    {
      public virtual int CustomerID { get; private set; }
      public virtual CustomerPhoto CustomerPhoto { get; set; }
      /* public virtual Other crap */
    
    }
    
    public class CustomerPhoto
    {
      public virtual Customer Customer { get; set; }
      public virtual Byte[] Photograph { get; set; }
    }
    
    public class CustomerPhotoMap : ClassMap<CustomerPhoto>
    {
        public CustomerPhotoMap()
        {
            Id(x => x.Id)
                .Column("CustomerID")
                .GeneratedBy.Foreign("Customer");
    
            Map(x => x.Photograph).Length(Int32.MaxValue);
        }
    }
    
    public class CustomerMap : ClassMap<Customer>
    {
        public CustomerMap()
        {
    
            Id(x => x.CustomerID).GeneratedBy.Identity()
                .Column("CustomerID");
    
            HasOne(x => x.CustomerPhoto)
                .Cascade.All();
    
        }
    }