2010-04-26 12 views
5

Bien, ayer logré obtener las últimas compilaciones troncales de NHibernate y FluentNHibernate para trabajar con mi último pequeño proyecto. (Estoy trabajando en una aplicación de seguimiento de errores.) Creé una buena capa de acceso a datos usando el patrón Repositorio.¿Cómo ajustar el mapeador automático de FluentNHibernate?

Decidí que mis entidades no son nada especiales, y también que con la madurez actual de los ORM, no quiero crear la base de datos a mano. Por lo tanto, elegí utilizar la función de asignación automática de FluentNHibernate con la propiedad "hbm2ddl.auto" de NHibernate configurada como "crear".

Realmente funciona como un encanto. Puse la configuración de NHibernate en el archivo de configuración del dominio de mi aplicación, lo configuré y comencé a jugar con él. (Por el momento, creé algunas pruebas unitarias solamente). Creó todas las tablas en la base de datos y todo lo que necesito para ello. Incluso mapeó mis relaciones de muchos a muchos correctamente.

Sin embargo, hay algunos fallos pequeños:

  • Todas las columnas creadas en la base de datos permiten nula. Entiendo que no puede predecir qué propiedades deberían permitir nulo y cuáles no, pero al menos me gustaría decir que debería permitir null solo para aquellos tipos para los que null tiene sentido en .NET (por ejemplo, no los tipos de valor anulables no deberían permitir nulo).
  • Todas las columnas nvarchar y varbinary que creó tienen una longitud predeterminada de 255. Preferiría tenerlas en max en lugar de eso.

¿Hay alguna manera de decirle al auto mapeador acerca de las dos simples reglas anteriores?

Si la respuesta es no, ¿funcionará correctamente si modifico las tablas que creó? (Por lo tanto, si fijo algunas columnas no permitir nula, y cambiar la longitud permitida por alguna otra, será correctamente trabajar con ellos?)

edición final: Muchas gracias a todos los que se redujo en y ayudó a salir. Todos mis problemas con Fluent se resuelven ahora.

Respuesta

6

Puede utilizar Anulaciones automáticas de asignación para cambiar el funcionamiento del Auto Mapper, y también puede definir Convenciones, que en su lugar utilizará el auto mapeador.

Aquí es un ejemplo de cómo usar tanto las convenciones y las anulaciones:

var mappings = new AutoPersistenceModel(); 
mappings.Conventions.Setup(s => s.Add<ColumnNullabilityConvention>()); 
mappings.UseOverridesFromAssemblyOf<AssemblyName>(); 

// This convention will set all properties to be not nullable 

public class ColumnNullabilityConvention: IPropertyConvention, IPropertyConventionAcceptance 
{ 
    public void Accept(IAcceptanceCriteria<IPropertyInspector> criteria) 
    { 
     criteria.Expect(x => x.Nullable, Is.Not.Set); 
    } 

    public void Apply(IPropertyInstance instance) 
    { 
     instance.Not.Nullable(); 
    } 
} 

// This override will change "string" to use "text" instead of "varchar(255)". 
// Also set the property to be not nullable 

public class SomeOverrideInTheSameAssembly : IAutoMappingOverride<TypeName> 
{ 
    public void Override(AutoMapping<TypeName> mapping) 
    { 
     mapping.Map(x => x.Property).CustomType("StringClob").CustomSqlType("text"); 
     mapping.Map(x => x.Property).Not.Nullable(); 
    } 
}  

comprobar estos enlaces para más ejemplos:

+0

¡Muchas gracias! Me las arreglé para que funcione con el siguiente código: persistenceModel.Conventions.Add (ConventionBuilder.Property.Always (x => x.Length (16000))); Esto es un poco hacky, porque en SQL Server, el 16000 lo establecerá en MAX, pero puede no ser bueno para otros servidores de bases de datos. ¿Hay una manera genérica de hacerlo? – Venemo

+0

No realmente. En general, debe establecerlo en el tipo personalizado "StringClob", porque eso debería significar que NHibernate es un tipo de "texto", pero aun así algunos proveedores de bases de datos NHibernate (como PostgreSQL) lo ignorarán. Es por eso que, por ejemplo, en mi ejemplo de Override he utilizado tanto el CustomType como la declaración CustomSqlType, para configurarlo en "texto". Alternativamente, si cambia el esquema de la base de datos debajo, a NHibernate no le importará si es varchar o algo más grande (texto, blob, etc.). Pero esta tampoco es una buena solución debido a muchas cosas obvias. – SztupY

+0

De acuerdo, lo dejaré como está por el momento. Por cierto, es agradable ver a otro húngaro aquí. :) – Venemo

1

No es muy conocido, pero puede establecer muchas convenciones desde la sección Asignaciones en su código de configuración, p.

Fluently.Configure() 
    .Database(/* database config */) 
    .Mappings(m => 
    { 
    m.FluentMappings 
     .AddFromAssemblyOf<Entity>() 
     .Conventions.Add(PrimaryKey.Name.Is(x => "ID")); 
    }) 

para establecer una convención de clave primaria.

Editar: Aclaración de lo que hace la convención PrimaryKey:

La convención PrimaryKey se utiliza para especificar qué la columna de la clave primaria es, no la propiedad. Descubrir la propiedad es un puro ejercicio de automatización , mientras que las convenciones se aplican a ClassMaps y automatizaciones. - James Gregory

Esta es la lista de convenios compatibles (desde el 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") 

Ver The Simplest Conventions sección en el wiki de HNF.

+0

Muchas gracias por su respuesta. Me las arreglé para que funcionara usando algunas convenciones personalizadas. Sin embargo, después de revisar la wiki, hay una cosa más que me molesta. No puedo hacer que PrimaryKey.Name.Is (x => "ID") funcione correctamente. – Venemo

+1

Lo siento, nunca he usado la convención de PrimaryKey. Acabo de copiar el ejemplo de la wiki. Podría ser un error. Le sugiero que publique una pregunta en el foro de soporte de FNH - http://support.fluentnhibernate.org/ –

+0

Lo haré, gracias. – Venemo

3

Para sus problemas de Id, necesita cambiar la configuración FindIdentity. Está cubierto en el automapping wiki page, aunque brevemente.

debe ir algo como esto:

AutoMap.AssemblyOf<Entity>() // your usual setup 
    .Setup(s => 
    { 
    s.FindIdentity = m => m.Name == "ID"; 
    }); 

Lo que esto hace es instruir al AutoMapper usar su nuevo lambda (m => m.Name == "ID") cuando se trata de descubrir documentos de identidad. m es la propiedad/miembro, y esta lambda se llama para cada propiedad en cada entidad; lo que sea que devuelva cierto es la identificación.

+0

@James, entonces, ¿por qué la convención PrimaryKey no funcionó para él? ¿Error en FNH? Mal uso del método? –

+0

La convención 'PrimaryKey' se usa para especificar qué es * la columna * de la clave primaria, no la propiedad. Descubrir la propiedad es un ejercicio puro de automatización, mientras que las convenciones se aplican a ClassMaps y automatismos. –

+0

Gracias por la aclaración, supongo que el nombre nos engañó tanto a Venemo como a mí. Editaré mi respuesta. –

Cuestiones relacionadas