NHibernate与多个值的三元关联 - 如何以一种很好的方式映射

Posted

技术标签:

【中文标题】NHibernate与多个值的三元关联 - 如何以一种很好的方式映射【英文标题】:NHibernate ternary association with multiple values - how to map in a nice way 【发布时间】:2011-05-12 22:30:54 【问题描述】:

我已经问过一个类似的问题,但我已经放弃了解决这个问题的想法,所以我希望得到一些帮助,以一种简洁的方式解决这个问题。

我有桌子

Image - (Id, Name, RelativeFilePath)
ImageFilter - (Id, Type)
ImageContext - (Id, Name, ...)
ImageContextImage - (Id, ImageContextId, ImageId, ImageFilterId)

数据示例:

ImageContextImage      Id        ImageContextId         ImageId        ImageFilterId
                       1         1                      1              1
                       2         1                      1              2
                       3         2                      1              1
                       4         3                      2              1

如您所见,上下文中的图像可以应用多个过滤器。

我所有的实体都很简单,除了上面的这个映射。目前我有

ImageContext
    public virtual int Id
    public virtual string Name
    public virtual IList<ImageContextImage> Images

ImageContextImage
    public virtual int Id
    public virtual ImageContext Context
    public virtual Image Image
    public virtual ImageFilter ImageFilter

上面很容易映射,但是对于每个图像,我会得到多个 ImageContextImage 对象。我宁愿让 ImageContextImage 包含一个 ImageFilter 列表,这样我就可以简单地遍历该集合。我尝试了很多 AsTernaryAssociation() 的排列,它抱怨我需要一个字典,但我希望每个键有多个值!有什么想法吗?

有什么想法吗?谢谢!

【问题讨论】:

能否更改数据库架构(例如添加表、列等...)? @Jakub 嗯,在某种程度上。 ImageFilter 必须能够添加到多个图像和 ImageContexts。那你有什么想法吗? :) 【参考方案1】:

三元关联可以替换为二元关联,但替换后会出现一个新实体 (Removing Ternary relationship types)。在您的情况下,它是 ImageContextImage 实体,困难的部分是为此类实体找到最佳名称。您的示例非常接近此替换。

ImageContextImage 实体:

public virtual int Id  get; set; 
public virtual Image Image  get; set; 
public virtual ImageContext Context  get; set; 
public virtual IList<ImageFilter> Filters  get; set; 

它正在映射:

Id(x => x.Id);
References(x => x.Image);
References(x => x.Context);
HasManyToMany(x => x.Filters); // filters are referenced via many-to-many relation

ImageContext 实体:

public virtual int Id  get; set; 
public virtual string Name  get; set; 
public virtual IList<ImageContextImage> ImageContextImageList  get; set; 

它正在映射:

Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.ImageContextImageList)
    .Inverse(); // to aggregate all ImageContextImage that are fererencing this instnstance of ImageContext
    .KeyColumn("Context_id");

对应的数据库架构略有不同:

ImageContextImage(Id, Image_id, Context_id)

并且必须为多对多关系创建新的关联表:

ImageFilterToImageContextImage(ImageContextImage_id, ImageFilter_id)

请注意,这只是一种可能方法的草图。许多细节取决于您的问题领域,并且必须在准备好投入生产之前进行调整:) - 例如级联。

我从未使用过 AsTernaryAssociation,但它似乎很有趣。稍后我会调查它,谢谢你的启发:)。

编辑: 三元关联可以通过稍微不同的映射(使用复合元素)来实现,但仍然有额外的实体 - ImageContextImage 在这种情况下被映射为组件:

public class ImageContext

    public virtual int Id  get; set; 
    public virtual string Name  get; set; 
    public virtual IList<ImageContextImage> ImageContextImageList  get; set; 

    public ImageContext()
    
        ImageContextImageList = new List<ImageContextImage>();
    


public class ImageContextMap : ClassMap<ImageContext>

    public ImageContextMap()
    
        Id(x => x.Id);
        Map(x => x.Name);
        HasMany(x => x.ImageContextImageList).Component(c =>
        
            c.References(x => x.Image);
            c.References(x => x.Filter);
        ).Cascade.AllDeleteOrphan();
    


public class ImageContextImage

    public virtual Image Image  get; set; 
    public virtual ImageFilter Filter  get; set; 

ImageContext 类可以通过这些方法进行扩展,使事情变得更简单:

public virtual IEnumerable<Image> AssociatedImages

    get
    
        return ImageContextImageList.Select(x => x.Image).Distinct().ToList();
    


public virtual IEnumerable<ImageFilter> GetFilters(Image image)

    return ImageContextImageList.Where(x => x.Image == image).Select(x => x.Filter).ToList();

AsTernaryAssociation 没有成功。

【讨论】:

嘿,谢谢!里面有很多有趣的东西......在我决定采用哪种方法之前,我需要安静地仔细阅读它,但我认为我可以走上正确的轨道。 :)

以上是关于NHibernate与多个值的三元关联 - 如何以一种很好的方式映射的主要内容,如果未能解决你的问题,请参考以下文章

Fluent NHibernate 仅级联删除关联记录

当两个或多个表关联在一起时,如何在查询中得到有空值的行?

NHibernate总结

NHibernate:检索非空一对一关联类的条件表达式

如何在多个实体到另一个实体之间创建 NHibernate 关系映射(即继承映射)

如何最好地在 NHibernate 中检索和更新这些对象?