Свободный NHibernate - как сопоставить подкласс один к одному? - PullRequest
7 голосов
/ 17 ноября 2008

Предположим, у меня есть три класса. Допустимо создание экземпляра A, но есть также особые случаи B и D, которые подкласс A, добавляя дополнительную информацию.

Как мне сделать файлы сопоставления для этого в (свободно) NHibernate?

public class A
{
    public int ID { get; set;}
    public string CommonProperty1 { get; set; }
    public string CommonProperty2 { get; set; }
}

public class B : A
{
    public string BSpecificProperty1 { get; set; } //not null
    public string BSpecificProperty2 { get; set; } //not null
}

public class D : A
{
    public string DSpecificProperty { get; set; } //not null
}

Я попробовал следующее, но это совсем не работает:

public class AMap : ClassMap<A>
{
    public AMap()
    {
        Id(x => x.ID);

        Map(x => x.CommonProperty1);
        Map(x => x.CommonProperty2);
    }
}

public class BMap : ClassMap<B>
{
    public BMap()
    {
        References(x => x.ID);
        Map(x => x.BSpecificProperty1)
            .CanNotBeNull();
        Map(x => x.BSpecificProperty2)
            .CanNotBeNull();
    }
}

public class DMap : ClassMap<D>
{
    public DMap()
    {
        References(x => x.ID);

        Map(x => x.DSpecificProperty)
            .CanNotBeNull();
    }
}

Ответы [ 2 ]

7 голосов
/ 18 ноября 2008

Я не уверен, что понимаю, что вы имеете в виду под «сопоставлением подкласса один-к-одному», но если вы хотите отобразить наследование, когда подклассы имеют свойства, которые не могут быть обнуляемыми, вы можете сделать это в Fluent- NHibernate:

// Domain classes
public class Animal
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class Cat : Animal
{
    public virtual int WhiskerLength { get; set; }
    public virtual int ClawCount { get; set; }
}

public class Dog : Animal
{
    public virtual int TailWagRate { get; set; }
}



// Mapping file
public class AnimalMap : ClassMap<Animal>
{
    public AnimalMap()
    {
        Id(x => x.Id)
            .WithUnsavedValue(0)
            .GeneratedBy.Native();

        Map(x => x.Name);

        var catMap = JoinedSubClass<Cat>("CatId", sm => sm.Map(x => x.Id));

        catMap.Map(x => x.WhiskerLength)
            .CanNotBeNull();
        catMap.Map(x => x.ClawCount)
            .CanNotBeNull();

        JoinedSubClass<Dog>("DogId", sm => sm.Map(x => x.Id))
            .Map(x => x.TailWagRate)
                .CanNotBeNull();
    }
}

Поскольку вы хотите, чтобы свойства подклассов были ненулевыми, вы должны использовать способ моделирования наследования для таблицы на класс (join-subclass). Это связано с тем, что для каждой таблицы требуется, чтобы все свойства подкласса обнулялись.

Надеюсь, это поможет.

/ Erik

5 голосов
/ 23 июля 2009

Синтаксис, возможно, изменился в FNH с момента публикации Эрика, но его пример верен цели. Вот некоторый код, который я использовал на основе поста Эрика для проработки через FNH двух стратегий подкласса FNH, о которых я знаю сейчас (SubClass (закомментированный код ниже, и JoinedSubClass). Кроме того, я видел другие имена, используемые для описания те же стратегии, в том числе в документах NHibernate, что немного сбивает с толку, когда это плохо для вас. (https://www.hibernate.org/hib_docs/nhibernate/html/inheritance.html).

// Domain classes
public class Animal : Entity
{
    public virtual string Name { get; set; }
    public virtual string Unwanted { get; set; }
}

public class Cat : Animal
{
    public virtual int WhiskerLength { get; set; }
    public virtual int ClawCount { get; set; }
}

public class Dog : Animal
{
    public virtual int TailWagRate { get; set; }
}

public class Boxer : Dog
{
    public string DroolBucket { get; set; }
}

public class AnimalMapJoinedSubclassOverride : IAutoMappingOverride<Animal>
{
    public void Override(AutoMap<Animal> mapping) {
        mapping.Map(x => x.Name);

        mapping.IgnoreProperty(x => x.Unwanted);

        mapping.JoinedSubClass("CatId", CatMap.AsJoinedSubClass());
        mapping.JoinedSubClass("DogId", DogMap.AsJoinedSubClass());
        //mapping.DiscriminateSubClassesOnColumn("Type")
        //    .SubClass<Cat>("CatId", CatMap.AsSubClass())
        //    .SubClass<Dog>("CatId", DogMap.AsSubClass());
    }
}

public class CatMap
{
    public static Action<JoinedSubClassPart<Cat>> AsJoinedSubClass()
    {
        return part =>
        {
            part.Map(x => x.ClawCount).Not.Nullable();
            part.Map(x => x.WhiskerLength).Not.Nullable();
        };
    }

    public static Action<SubClassPart<Cat>> AsSubClass()
    {
        return part =>
        {
            part.Map(x => x.ClawCount);
            part.Map(x => x.WhiskerLength);
        };
    }
}

public class DogMap
{
    public static Action<JoinedSubClassPart<Dog>> AsJoinedSubClass()
    {
        return sub =>
        {
            sub.Map(x => x.TailWagRate).Not.Nullable();
        };
    }

    public static Action<SubClassPart<Dog>> AsSubClass()
    {
        return sub =>
        {
            sub.Map(x => x.TailWagRate);
        };
    }
}

public class BoxerMap
{
    public static Action<JoinedSubClassPart<Boxer>> AsJoinedSubClass()
    {
        return sub =>
        {
            sub.Map(x => x.DroolBucket);
        };
    }

    public static Action<SubClassPart<Boxer>> AsSubClass()
    {
        return sub =>
        {
            sub.Map(x => x.DroolBucket);
        };
    }
}
...