Избегайте указания ключевого столбца в сценарии с двойной связью - PullRequest
5 голосов
/ 05 ноября 2011

Предположим, у меня есть следующие два класса:

public class User : Entity
{
    public virtual IList<Item> Items { get; set; }
}

public class Item : Entity
{
    public virtual User Owner { get; set; }
}

Я создал два класса отображения:

public class UserMap : ClassMap<User>
{
    public UserMap()
    {
        Id(x => x.Id);
        HasMany(x => x.Items);
    }
}

public class ItemMap : ClassMap<Item>
{
    public ItemMap()
    {
        Id(x => x.Id);
        References(x => x.Owner);
    }
}

В результате получится таблица Item, в которой есть столбец UserId и столбец OwnerId.Когда я использую KeyColumn("OwnerId") для сопоставления HasMany, он работает только со столбцом OwnerId, но я бы хотел этого избежать.Есть ли способ сообщить NHibernate, использовать столбец, созданный сопоставлением в ItemMap?

Почему я хочу избежать явного указания столбца:
Имя столбца OwnerId генерируется автоматическина основании названия имущества и некоторых правил.Если я изменю либо правила, либо имя свойства, мне нужно помнить, что тоже нужно изменить KeyColumn.Так что, по сути, это не рефакторинг сохранения.

1 Ответ

2 голосов
/ 14 ноября 2011

Обновлено: исправлена ​​ошибка

, если вы применяете правила на картах, тогда

public static void KeyColumnFromReference<TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map, Expression<Func<TChild, object>> referenceprop)
{
    string propertyname = GetPropertyName(referenceprop);
    var column = ((IMappingProvider)map).GetClassMapping()
        .References.First(m => m.Name == propertyname)
        .Columns.First().Name;

    collectionmap.KeyColumn(column);
}

public static void KeyColumnFromReference<T, TChild>(
    this OneToManyPart<TChild> collectionmap, ClassMap<TChild> map)
{
    var column = ((IMappingProvider)map).GetClassMapping()
        .References.First(m => m.Type == typeof(TChild))
        .Columns.First().Name;

    collectionmap.KeyColumn(column);
}

public UserMap()
{
    HasMany(x => x.Items)
        .KeyColumnFromReference<User, Item>(new ItemMap());

    // or

    HasMany(x => x.Items)
        .KeyColumnFromReference(new ItemMap(), u => u.Owner);
}

, если вы применяете правила в качестве соглашений, вам нужно реализовать IHasManyConvention и применить то же самоеправила для EntityType и имени свойства (которое вы должны получить путем отражения от ChildType)

Обновление:

class ForeignKeyConvention : IHasManyConvention
{
    public void Apply(IOneToManyCollectionInstance instance)
    {
        // to force the compiler to take the Name property and not the Name method
        string propertyName = ((ICollectionInspector)instance).Name;

        // should be equal to the convention for the reference key column
        instance.Key.Column(propertyName + instance.EntityType.Name + "id");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...