views:

33

answers:

1

Hi,

Got a bit of an odd situation which I'm trying to map in Fluent nHibernate and failing. I have an Asset object which contains both an Image object and a File object. The Id of Image and File is identical, and the Image object contains a File object. This situation arises because an Image is always also a File (which is why the Id's have to match) but a File is not always an image.

I've mapped this as follows:

AssetMap

Public Sub New()
    Id(Function(x) x.Id)
    Map(Function(x) x.DisplayOrder)
    Map(Function(x) x.Text).Length(10000)
    Map(Function(x) x.Title)
    Map(Function(x) x.Width)
    Map(Function(x) x.Height)
    References(Function(x) x.Image).LazyLoad().Cascade.All()
    References(Function(x) x.File).LazyLoad().Cascade.All()
    References(Function(x) x.Row).Cascade().All()
    Map(Function(x) x.AssetType).CustomType(Of AssetType)()
End Sub

ImageMap

Public Sub New()
    Id(Function(x) x.ID)
    Map(Function(x) x.Height)
    Map(Function(x) x.Width)
    Map(Function(x) x.AltText)
    Map(Function(x) x.ToolTip)
    Map(Function(x) x.ImageStatus).CustomType(Of ImageStatus)()
    References(Function(x) x.Product).Nullable()
    HasOne(Function(x) x.File).Constrained()
    References(Function(x) x.ViewTag)
    HasManyToMany(Function(x As Image) x.ProductOptionValues).Table("ImageVsProductOptionValues").LazyLoad().Cascade.All()
    HasManyToMany(Function(x As Image) x.MappedCategories).Table("CategoryVsImage").LazyLoad().Cascade.All().Inverse()
End Sub

Filemap

Public Sub New()
    Id(Function(x) x.Id)
    Map(Function(x) x.Data).LazyLoad().Length(Integer.MaxValue)
    Map(Function(x) x.MimeType)
    Map(Function(x) x.Size)
    Map(Function(x) x.Filename)
    Map(Function(x) x.LastDateModified)
    Map(Function(x) x.DateCreated)
End Sub

I've run into trouble trying to use the following code to create a new image and add it to an Asset and save it.

        If oAsset.Image Is Nothing Then
            currentImage = New CMS.DataTransferObjects.Image
            currentFile = New CMS.DataTransferObjects.File
        Else
            currentImage = oAsset.Image
            currentFile = oAsset.File
        End If

        currentFile.Data = ms.ToArray
        currentFile.MimeType = mimeType
        currentFile.Filename = filImgUpload.FileName
        currentFile.Size = filImgUpload.ContentLength
        currentImage.Width = CInt(Utils.Convert.ToInt64(UploadedImage.PhysicalDimension.Width))
        currentImage.Height = CInt(Utils.Convert.ToInt64(UploadedImage.PhysicalDimension.Height))

        If oAsset.Image Is Nothing Then
            oAsset.Image = currentImage
            oAsset.File = currentFile
        Else
            'currentImage = oAsset.Image
            'currentFile = oAsset.File
        End If

I then call an nHibernate manager and try up .Update the Asset, which results in the following error:

The INSERT statement conflicted with the FOREIGN KEY constraint "FK30EBACDFED57EBE9". The conflict occurred in database "BDM1_TestBed", table "dbo.File", column 'Id'.

Can anyone help sort out this mess - I assume my mappings are wrong, but I'm not sure how to improve them?

A: 

Before I post my thoughts, I'd reccomend NHibernate Profiler, if you're not using it already. It's saved my butt countless times with mapping issues, and there's a free trial if you want to just try it out. Usually, in a situation like this, seeing the SQL generated by NHIbernate (via NHProf) has led me to the solution. Check it out here: http://www.nhprof.com/

As for my thoughts, It does look like your mapping is incomplete. Try adding ForeignKey to your AssetMap, like so:

References(Function(x) x.File)
    .ForeignKey("Id")
    .LazyLoad()
    .Cascade.All()

You will probably need to do the same for the ImageMap

From what I recall, Fluent NHibernate will automatically use the convention "Tablename_Id" if you don't specify the name explicitly.

Hope that helps. Let me know if that doesn't do it.

Brandon Satrom