Могу ли я сделать соглашение о внешнем ключе Fluent NHibernate, которое включает имя родительского ключа? - PullRequest
9 голосов
/ 18 февраля 2010

У меня есть схема базы данных, где соглашение для имени внешнего ключа:

ForeignTable.Name + ForeignTable.PrimaryKeyName

Итак, для таблицы Child, ссылающейся на таблицу Parent со столбцом первичного ключа с именем Key, внешний ключ будет выглядеть как ParentKey.

Есть ли способ создать это соглашение в моем отображении Fluent NHibernate?

В настоящее время я использую реализацию ForeignKeyConvention, например, так:

public class ForeignKeyNamingConvention : ForeignKeyConvention
{
    protected override string GetKeyName(PropertyInfo property, Type type)
    {
        if (property == null)
        {
            // Relationship is many-to-many, one-to-many or join.
            if (type == null)
                throw new ArgumentNullException("type");

            return type.Name + "ID";
        }

        // Relationship is many-to-one.
        return property.Name + "ID";
    }
}

Это работает точно так, как я хочу для всех типов, у которых «ID» является первичным ключом.То, что я хотел бы сделать, это заменить константу "ID" на имя первичного ключа типа, на который ссылаются.

Если в настоящее время это невозможно с Fluent NHibernate, я рад принять этоответить.

Ответы [ 3 ]

7 голосов
/ 25 февраля 2010

Взгляните на соглашений и особенно на реализацию пользовательского соглашения о внешних ключах.


UPDATE:

Вот пример. Предполагая следующий домен:

public class Parent
{
    public virtual int Id { get; set; }
}

public class Child
{
    public virtual string Id { get; set; }
    public virtual Parent Parent { get; set; }
}

, который должен быть сопоставлен с этой схемой:

create table Child(
    Id integer primary key, 
    ParentId integer
)

create table Parent(
    Id integer primary key
)

Вы можете использовать это соглашение:

public class CustomForeignKeyConvention : IReferenceConvention
{
    public void Apply(IManyToOneInstance instance)
    {
        instance.Column(instance.Class.Name + "Id");
    }
}

и для создания фабрики сеансов:

var sf = Fluently
    .Configure()
    .Database(
        SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql()
    )
    .Mappings(
        m => m.AutoMappings.Add(AutoMap
            .AssemblyOf<Parent>()
            .Where(t => t.Namespace == "Entities")
            .Conventions.Add<CustomForeignKeyConvention>()
        )
    )
    .BuildSessionFactory();
3 голосов
/ 04 марта 2010

Если вы можете получить Mapping<T> для класса, вы можете получить имя его столбца Id.

public class MyForeignKeyConvention: ForeignKeyConvention
{
    public static IList<IMappingProvider> Mappings = new List<IMappingProvider>();

    protected override string GetKeyName( System.Reflection.PropertyInfo property, Type type )
    {
        var pk = "Id";

        var model = new PersistenceModel();
        foreach( var map in Mappings ) {
            model.Add( map );
        }

        try {
            var mymodel = (IdMapping) model.BuildMappings()
                .First( x => x.Classes.FirstOrDefault( c => c.Type == type ) != null )
                .Classes.First().Id;

            Func<IdMapping, string> getname = x => x.Columns.First().Name;
            pk = getname( mymodel );
        } catch {
        }

        if (property == null) {
            return type.Name + pk;
        }
        return type.Name + property.Name;
    }
}

Мы можем получить объект Mapping с небольшим количеством элементов.

Конструкторы ClassMap<T> могут передавать this в нашу коллекцию Mappers.

Для AutoMapping<T> мы можем использовать Override следующим образом.

.Mappings( m => m.AutoMappings.Add( AutoMap.AssemblyOf<FOO>()
    .Override<User>( u => {
        u.Id( x => x.Id ).Column( "UID" );
        MyForeignKeyConvention.Mappings.Add( u );
    }
)
1 голос
/ 12 февраля 2014

Для общесистемного соглашения я считаю, что это лучше всего послужит цели. (Я не был уверен, стоит ли включать весь текст или только часть здесь, так как я ответил на него здесь уже)

Вот решение со ссылками на текущую документацию по Fluent NHibernate & autopping.

Проблема (простой пример):

Допустим, у вас есть простой пример (из вики-администратора) с сущностью и ее объектами значений в списке:

public class Product
{
  public virtual int Id { get; set; }
  //..
  public virtual Shelf { get; set; }
}

public class Shelf
{
  public virtual int Id { get;  set; }
  public virtual IList<Product> Products { get; set; }

  public Shelf()
  {
    Products = new List<Product>();
  }
}

С таблицами, например,

Shelf 
id int identity

Product 
id int identity 
shelfid int

и внешним ключом для Shelid -> Shelf.Id


Вы получите сообщение об ошибке: неверное имя столбца ... shelf_id


Решение:

Добавьте соглашение, оно может быть системным или более ограниченным.

ForeignKey.EndsWith("Id")

Пример кода:

var cfg = new StoreConfiguration();
var sessionFactory = Fluently.Configure()
  .Database(/* database config */)
  .Mappings(m =>
    m.AutoMappings.Add(
      AutoMap.AssemblyOf<Product>(cfg)
          .Conventions.Setup(c =>
              {
                  c.Add(ForeignKey.EndsWith("Id"));
              }
    )
  .BuildSessionFactory();

Теперь он будет автоматически преобразовывать столбец ShelfId в свойство Shelf в Product.


Подробнее

Wiki для автоматического сопоставления

Table.Is(x => x.EntityType.Name + "Table")
PrimaryKey.Name.Is(x => "ID")
AutoImport.Never()
DefaultAccess.Field()
DefaultCascade.All()
DefaultLazy.Always()
DynamicInsert.AlwaysTrue()
DynamicUpdate.AlwaysTrue()
OptimisticLock.Is(x => x.Dirty())
Cache.Is(x => x.AsReadOnly())
ForeignKey.EndsWith("ID")

Подробнее о соглашениях об автоматическом использовании Fluent NHibernate

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