Свободное автоматическое отображение NHibernate: Как настроить имя таблицы подкласса и имя ключевого столбца? - PullRequest
4 голосов
/ 28 марта 2011

Я думаю, что об этом уже спрашивали, но я гуглил час, но не смог найти ответ.

Допустим, у меня есть следующие 2 модели:

public class Organism
{
    public virtual int Id { get; private set; }
}

public class Animal : Organism
{
}

Я хочу, чтобы Fluent NHibernate создал для меня следующие таблицы:

OrganismTable
    OrganismId

AnimalTable
    AnimalId

Это может быть легко достигнуто с помощью ручного отображения:

public class OrganismMappinig : ClassMap<Organism>
{
    public OrganismMappinig()
    {
        Table("OrganismTable");
        Id(x => x.Id).Column("OrganismId");
    }
}

public class AnimalMapping : SubclassMap<Animal>
{
    public AnimalMapping()
    {
        Table("AnimalTable");
        KeyColumn("AnimalId");
    }
}  

Но я не могу получить тот же результат, используя автоподстановку. Я пытался добавить следующие условные обозначения:

public class TableNameConvension : IClassConvention, IClassConventionAcceptance
{
    public void Apply(IClassInstance instance)
    {
        instance.Table(instance.EntityType.Name + "Table");
    }

    public void Accept(IAcceptanceCriteria<IClassInspector> criteria)
    {
        criteria.Expect(x => x.TableName, Is.Not.Set);
    }
}

public class PrimaryKeyNameConvention : IIdConvention
{
    public void Apply(IIdentityInstance instance)
    {
        instance.Column(instance.EntityType.Name + "Id");
    }
}

Он создал эти 2 таблицы:

OrganismTable (correct)
    OrganismId (correct)

Animal (wrong, should be "AnimalTable")
    Organism_id (wrong, should be "AnimalId")

Я также пытался добавить:

public class ForeignKeyColumnNameConvention : ForeignKeyConvention
{
    protected override string GetKeyName(Member property, Type type)
    {
        if (property == null)
            return type.Name + "Id";

        return property.Name + "Id";
    }
}

Он создал эти 2 таблицы:

OrganismTable (correct)
    OrganismId (correct)

Animal (wrong, should be "AnimalTable")
    OrganismId (wrong, should be "AnimalId")

Я также пытался добавить:

public class AnimalOverride : IAutoMappingOverride<Animal>
{
    public void Override(AutoMapping<Animal> mapping)
    {
        mapping.Table("AnimalTable");
        mapping.Id(x => x.Id).Column("AnimalId");
    }
}

Созданы следующие таблицы:

OrganismTable (correct)
    OrganismId (correct)

AnimalTable (correct)
    OrganismId (wrong, should be "AnimalId")

Это правильно устанавливает имя таблицы в «AnimalTable» (но это требует слишком много ручного набора текста, было бы хорошо, если есть соглашение, которое может получить тот же результат), но не удалось установить имя ключевого столбца в «AnimalId». 1030 *

Ниже приведен мой код:

class Program
{
    static void Main(string[] args)
    {
        ISessionFactory sessionFactory = Fluently.Configure()
            .Database(MsSqlConfiguration
                          .MsSql2008.ConnectionString(connectionString)
                          .ShowSql())
            .Mappings(m => m.AutoMappings.Add(
                AutoMap.Assemblies(typeof(Organism).Assembly)
                    .Conventions.AddAssembly(typeof(Program).Assembly)
                    .UseOverridesFromAssembly(typeof(Program).Assembly)))
            .ExposeConfiguration(BuildSchema)
            .BuildConfiguration()
            .BuildSessionFactory();
    }

    static void BuildSchema(Configuration cfg)
    {
        new SchemaExport(cfg).Create(false, true);
    }
}

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

1 Ответ

8 голосов
/ 31 марта 2011

Когда FluentNHibernate выполняет автоматическое сопоставление, он использует таблицу для каждого конкретного класса для отображения иерархий наследования. Поскольку Organism и Animal являются конкретными типами, он генерирует две таблицы, OrganismTable и AnimalTable. OrganismTable хранит все свойства, общие для всех организмов. AnimalTable хранит только свойства, добавленные подклассом Animal. PK на AnimalTable также является FK для OrganismTable. Следовательно это затронуто вашим соглашением FK. Обратите внимание, что PKNameConvention вызывается только для организма, а не для животных. Аналогично FKColumnNameConvention вызывается только Animal. Поскольку Animal FK используется только для внутренней иерархии наследования, свойство имеет значение null. Следовательно вы получаете OrganismId как имя FK. Чтобы установить этот PK / FK, вам нужно использовать IJoinedSubclassConvention. (Я включил ваше TableNameConvention и PrimaryKeyNameConvention для полноты.)

public class TableNameConvension : IClassConvention, IClassConventionAcceptance {
    public void Apply(IClassInstance instance) {
        instance.Table(instance.EntityType.Name + "Table");
    }

    public void Accept(IAcceptanceCriteria<IClassInspector> criteria) {
        criteria.Expect(x => x.TableName, Is.Not.Set);
    }
}
public class PrimaryKeyNameConvention : IIdConvention {
    public void Apply(IIdentityInstance instance) {
        instance.Column(instance.EntityType.Name + "Id");
    }
}
public class JoinedSubclassIdConvention : IJoinedSubclassConvention
{
    public void Apply(IJoinedSubclassInstance instance) {
        instance.Table(instance.EntityType.Name + "Table");
        instance.Key.Column(instance.EntityType.Name + "Id");
    }
}

Это генерирует:

OrganismTable
    OrganismId

AnimalTable
    AnimalId

с FK из AnimalTable.AnimalId в OrganismTable.OrganismId.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...