Тройная ассоциация NHibernate с несколькими значениями - как правильно сопоставить - PullRequest
3 голосов
/ 13 мая 2011

Я задал похожий вопрос, но я отказался от идеи, которая у меня возникла, чтобы решить эту проблему, поэтому я хотел бы получить помощь в решении этой проблемы аккуратно.

У меня есть столы

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 (), и он жалуется, что мне нужен словарь, но я хочу несколько значений на ключ! Есть идеи?

Есть идеи? Спасибо!

1 Ответ

2 голосов
/ 20 мая 2011

Тернарная ассоциация может быть заменена двоичными ассоциациями, но после замены появится новая сущность ( Удаление тернарных типов отношений ). Это объект 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)

Обратите внимание, что это только набросок одного возможного подхода. Многие детали зависят от вашей проблемной области и должны быть настроены, прежде чем она будет готова к производству :) - например, .cascades.

Я никогда не использовал AsTernaryAssociation, но это кажется интересным. Я буду исследовать это позже, спасибо за вдохновение:).

EDIT: Тернарная ассоциация может быть реализована с помощью немного другого отображения (с использованием составного элемента), но есть еще дополнительная сущность - 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.

...