2010-12-07 26 views
0

Quelle est l'équivalent de < key column = "Person_id"/> dans Fluent NHibernate ??Fonction NHibernate fluide pour changer la colonne de clé du sac

<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]

Je cette cartographie:

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; } 
} 

Je ces deux tableaux:

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 
); 

Je suis en train de changer les contacts hasMany 'Clé de la colonne sur yyyy, Fluent NHibernate utilise par défaut Person_id. (Notez le P capital de person_id (je pense Fluent est d'avoir trop de convention-sur-configuration))

Si par hasard que ConventionBuilders ont une incidence sur le cas de problème de mon programme, voici comment je configurer mes conventions:

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(); 
    }    
} 

Et ce code ...

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

... produit:

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 
+0

Que voulez-vous dire « Changez à travers couramment "? – Phill

+0

Je suppose par votre cartographie en disant "FluentTry" que vous apprenez Fluent NHibernate. Je pense que vous devriez essayer quelque chose de basique, comme un simple mappage de personne, pas de conventions, juste configurer la configuration pour créer les tables pour vous afin que vous puissiez voir ce qu'il produit. – Phill

+0

Salut Phill, si ce serait utile, j'ai inclus mon code FNH –

Répondre

1

Je l'ai résolu maintenant (bonne chose NHibernate fluide est opensource). HasMany de la personne génère son nom de colonne de clé étrangère de collection keymapping, trouvé dans ToManyBase.cs (dans le code source de FNH), la valeur par défaut:

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

je prévois d'effacer la collection keymapping et rajoutez mon nom de colonne clé personnalisée (« yyyy »), mais une bonne chose que je ne ont pas besoin, FNH a déjà cette fonction, la fonction KeyColumn (en OneToManyPart.cs), c'est sa définition:

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

Ainsi, si le nom de champ de votre clé étrangère n'est pas sous la forme de ClassName + "_id", de côté à partir de l'ajout .Column (yourCustomizedFieldNameHere) dans vos collections de la classe racine Références (par ex. 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 

... vous devez également ajouter .KeyColumn (yourCustomizedFieldNameHere) à votre cartographie hasMany dans votre classe racine, à savoir:

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