Свободная функция NHibernate для смены ключевого столбца сумки - PullRequest
0 голосов
/ 07 декабря 2010

Что эквивалентно в Fluent NHibernate ??

  <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="FluentTry.Person, FluentTry, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="person">
    <id name="PersonId" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="person_id" />
      <generator class="identity" />
    </id>
    <bag inverse="true" name="Contacts" mutable="true">
      <key>
        <column name="Person_id" /> <!-- how to change this through Fluent? -->
      </key>
    </bag>

[EDIT]

У меня есть это отображение:

public class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {       
        Id(x => x.PersonId);
        Map(x => x.PersonName).Not.Nullable();
        Map(x => x.Birthdate).Not.Nullable();                   
        Component(x => x.Birthplace).ColumnPrefix("birthplace_");

        HasMany(x => x.Contacts).Inverse();

    }
}//PersonMap

public class ContactMap : ClassMap<Contact>
{
    public ContactMap()
    {           
        References(x => x.Owner).Column("yyyy");



        Id(x => x.ContactId).GeneratedBy.Sequence("contact_contact_id_seq");

        Map(x => x.Number);
        Map(x => x.Type);



    }

}//ContactMap

public class AddressComponentMap : ComponentMap<AddressComponent>
{
    public AddressComponentMap()
    {           

        // ConventionBuilder.Property.Always doesn't have an effect on Column method of Map of ComponentMap. We need to override it by ourselves
        Map(x => x.StreetNumber).Column("street_number");
        Map(x => x.Street).Column("street");
        Map(x => x.City).Column("city");
        Map(x => x.PostCode).Column("post_code");
    }
}//AddressComponentMap

    // POCOs...

public class Person
{
    public virtual int PersonId { get; set; }

    public virtual string PersonName { get; set; }
    public virtual DateTime Birthdate { get; set; }     
    public virtual AddressComponent Birthplace { get; set; }

    public virtual IList<Contact> Contacts { get; set; }
}

public class AddressComponent
{
    public virtual string StreetNumber { get; set; }
    public virtual string Street { get; set; }
    public virtual string City { get; set; }
    public virtual string PostCode { get; set; }

}

public class Contact
{
    public virtual Person Owner { get; set; }

    public virtual int ContactId { get; set; }

    public virtual string Number { get; set; }      
    public virtual string Type { get; set; }
}   

У меня есть эти дватаблицы:

CREATE TABLE person
(
  person_id serial NOT NULL PRIMARY KEY,
  person_name text NOT NULL,
  birthdate date NOT NULL,
  birthplace_street_number text NOT NULL,
  birthplace_street text NOT NULL,
  birthplace_city text NOT NULL,
  birthplace_post_code text NOT NULL
);

create table contact
(
yyyy int not null references person(person_id),
contact_id serial not null primary key,
number text not null,
type text not null
);

Я пытаюсь изменить ключевой столбец контактов HasMany на yyyy, для Fluent NHibernate по умолчанию задано Person_id.(Обратите внимание на заглавную букву P в Person_id (я думаю, что у Fluent слишком много соглашений о переконфигурации))

Если случайно, что ConventionBuilders влияет на проблемный случай моей программы, вот как я настраиваю свои соглашения:1018 *

    static ISessionFactory CreateSessionFactory()
    {

        return (ISessionFactory) Fluently.Configure()
            .Database
                (
                    PostgreSQLConfiguration.Standard.ConnectionString("Server=localhost;Database=fluent_try;User ID=postgres;Password=opensesame;")
                )
            .Mappings( m => m.FluentMappings.AddFromAssemblyOf<MainClass>()
                          .Conventions.Add(
                                           ConventionBuilder.Class.Always( x => x.Table( x.EntityType.Name.ToPostgresNamingConvention() )  )
                                           ,ConventionBuilder.Property.Always( x => x.Column(x.Name.ToPostgresNamingConvention() ) )
                                           ,ConventionBuilder.Id.Always( x => x.Column(x.Name.ToPostgresNamingConvention() ) )                                                                                       
                                           ) 

                          .ExportTo("/Users/Michael")
                          )         
            .BuildSessionFactory();
    }





public static class Helper
{
    public static string ToPostgresNamingConvention(this string s)
    {
        var r = new Regex(@"
            (?<=[A-Z])(?=[A-Z][a-z]) |
            (?<=[^A-Z])(?=[A-Z]) |
            (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);

        return r.Replace(s, "_").ToLower();
    }               
}

И этот код ...

foreach(Contact c in p.Contacts) // p doesn't have problems. Iterating its Contacts has
{
    Console.WriteLine("Contact: {0} {1}", c.Number, c.Type);
}

... производит:

Unhandled Exception: NHibernate.Exceptions.GenericADOException: 
could not initialize a collection: [FluentTry.Person.Contacts#1][SQL: SELECT 
contacts0_.Person_id as Person5_1_, contacts0_.contact_id as contact1_1_, 
contacts0_.contact_id as contact1_0_0_, contacts0_.number as number0_0_, contacts0_.type 
as type0_0_, contacts0_.yyyy as yyyy0_0_ FROM contact contacts0_ WHERE 
contacts0_.Person_id=?] ---> Npgsql.NpgsqlException:
column contacts0_.person_id does not exist
Severity: ERROR
Code: 42703

1 Ответ

1 голос
/ 07 декабря 2010

Я решил это сейчас (хорошо, что Fluent NHibernate с открытым исходным кодом).HasMany пользователя генерирует имя столбца внешнего ключа из коллекции keyMapping , найденной в ToManyBase.cs (в исходном коде FNH), по умолчанию:

keyMapping.AddDefaultColumn(new ColumnMapping { Name = entity.Name + "_id" });

Iпланирую очистить коллекцию keyMapping и повторно добавить мое настраиваемое имя столбца ключа («гггг»), но хорошо, что мне не нужно, у FNH уже есть эта функция, функция KeyColumn (в OneToManyPart.cs), это ее определение:

    public OneToManyPart<TChild> KeyColumn(string columnName)
    {
        Key(ke =>
        {
            ke.Columns.Clear();
            ke.Columns.Add(columnName);
        });
        return this;
    }

Итак, если имя поля вашего внешнего ключа не в форме ClassName + "_id", кроме добавления .Column (yourCustomizedFieldNameHere) в ваш корневой класс 'collection' Ссылки (например, ContactMap) ...

public class ContactMap : ClassMap<Contact>
{
    public ContactMap()
    {           
        References(x => x.Owner).Column("yyyy"); // must add .Column if your fieldname is not of Classaname + "_id" form

        Id(x => x.ContactId);

        Map(x => x.Number);
        Map(x => x.Type);           
    }

}//ContactMap

... вы также должны добавить .KeyColumn (yourCustomizedFieldNameHere) к вашему отображению HasMany в корневом классе,т.е.:

public class PersonMap : ClassMap<Person>
{
    public PersonMap()
    {       
        Id(x => x.PersonId);
        Map(x => x.PersonName).Not.Nullable();
        Map(x => x.Birthdate).Not.Nullable();                   
        Component(x => x.Birthplace).ColumnPrefix("birthplace_");

        HasMany(x => x.Contacts).KeyColumn("yyyy").Inverse(); // must add .KeyColumn

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