2009-02-05 14 views
9

Tengo una base de datos heredada en la que las tablas de transacciones se almacenan por nombres mensuales.Cómo utilizar Nhibernate con nombres de tablas dinámicos o variables como Jan08Tran, Feb08Tran, Mar08Tran

por ejemplo.

 Jan08Tran 
    Feb08Tran 

¿Cómo puedo usar NHibernate para trabajar con estas tablas?

Lea un poco acerca de la propiedad del nombre de la entidad, SubClass, etc., pero no puede encontrar una solución concreta.

+0

no. no. no. Su esquema de base de datos está mal. No hagas eso a las tablas. no hay una buena razón para (hacer eso), nunca. Agregue una columna de fecha que almacena la fecha de la transacción. Si le preocupa la agrupación/partición, la columna de fecha se convierte en el punto de pivote. – jim

+5

Gracias Jim por la preocupación. Pero como mencioné, esta es una base de datos heredada y no puedo cambiarla ahora, ya que está en anuncios de producción utilizados por al menos 400 de mis clientes. –

+0

¿Qué DB? En teoría, puede pasar a una única tabla particionada con una columna de fecha y luego crear vistas para cada tabla de mes y medio y eso resolverá el problema de hibernación y otros problemas. – jim

Respuesta

20

tuve una situación similar donde tenía que proporcionar una interfaz entre las aplicaciones compradas a que estaban en la producción y siendo utilizados por toneladas de diferentes sistemas. Este sistema tenía diferentes nombres de tabla a lo largo de dev, test y prod (ridículo ...) Mi solución fue dejar un marcador de posición para el número de tabla en la configuración de NHibernate así:

<class name="MyClass" table="MyTable[tableNumber]"> 

y luego implementar INamingStrategy similar a:

public class MyCustomNamingStrategy : INamingStrategy 
{ 
    public string ClassToTableName(string className) 
    { 
     return DefaultNamingStrategy.Instance.ClassToTableName(className); 
    } 

    public string PropertyToColumnName(string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.PropertyToColumnName(propertyName); 
    } 

    public string TableName(string tableName) 
    { 
     tableName = tableName.Replace("[tableNumber]", LocalSettings.TableNumber); 
     return DefaultNamingStrategy.Instance.TableName(tableName); 
    } 

    public string ColumnName(string columnName) 
    { 
     return DefaultNamingStrategy.Instance.ColumnName(columnName); 
    } 

    public string PropertyToTableName(string className, string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.PropertyToTableName(className, propertyName); 
    } 

    public string LogicalColumnName(string columnName, string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.LogicalColumnName(columnName, propertyName); 
    } 
} 

y después fijar la estrategia de nomenclatura en la configuración:

myConfiguration.SetNamingStrategy(new MyCustomNamingStrategy()); 

de esta manera el número de tabla se podría almacenar en el App.config y la aplicación podría ser movido a través de entornos sólo por el cambio de valores en el App.conf yo G. Estoy seguro de que podría encontrar una forma de usar esto para cambiar el nombre de la tabla a cualquier fecha que necesite ...

+0

realmente impresionante: D –

+0

¿Dónde establecer la estrategia de nombres en la configuración? ¿Y podemos usar ambas opciones de NHibernate, como la especificación directa del nombre físico y la asignación dinámica de nombres en un solo proyecto con una única base de datos? –

0

Santo # $% ^! =)

Creo que esto se puede lograr con IEntityPersister personalizado, pero esto no sería una tarea fácil.

No estoy seguro de eso, pero ¿es la vista actualizable de alguna ayuda?

0

Una opción más es usar SQL personalizado para hacer la persistencia o escribir sprocs para manejar los nombres de tabla cambiantes.

+0

Sí, pensé, pero SQL o sprocs personalizados desafiarán la ventaja real de usar NHibernate –

1

Se buscó mucho pero no se encontró nada específico, finalmente se avanzó línea por línea a través de la fuente NHibernate y se encontró la siguiente solución. Esto no es fácil, pero aún tiene una solución alternativa.

  1. Crear un nuevo classs SqlInterceptor que implementa IInterceptor
  2. En el método OnPrepareStatement puede cambiar el SQL como desea
  3. A continuación, añadir esta SqlInterceptor a sesionará aunque configuration.SetInterceptor(new SqlInterceptor());

siguiente es el código para SqlInterceptor

using System; 
using System.Collections; 
using NHibernate.SqlCommand; 
using NHibernate.Type; 

namespace NHibernate 
{ 
    [Serializable] 
    public class SqlInterceptor : IInterceptor 
    { 
     public virtual void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types) 
     { 
     } 

     public void OnCollectionRecreate(object collection, object key) 
     { 
     } 

     public void OnCollectionRemove(object collection, object key) 
     { 
     } 

     public void OnCollectionUpdate(object collection, object key) 
     { 
     } 

     public virtual bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, 
             string[] propertyNames, IType[] types) 
     { 
      return false; 
     } 

     public virtual bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types) 
     { 
      return false; 
     } 

     public virtual bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types) 
     { 
      return false; 
     } 

     public virtual void PostFlush(ICollection entities) 
     { 
     } 

     public virtual void PreFlush(ICollection entitites) 
     { 
     } 

     public virtual bool? IsTransient(object entity) 
     { 
      return null; 
     } 

     public virtual object Instantiate(string clazz, EntityMode entityMode, object id) 
     { 
      return null; 
     } 

     public string GetEntityName(object entity) 
     { 
      return null; 
     } 

     public object GetEntity(string entityName, object id) 
     { 
      return null; 
     } 

     public virtual int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, 
             string[] propertyNames, IType[] types) 
     { 
      return null; 
     } 

     public virtual void AfterTransactionBegin(ITransaction tx) 
     { 
     } 

     public virtual void BeforeTransactionCompletion(ITransaction tx) 
     { 
     } 

     public virtual void AfterTransactionCompletion(ITransaction tx) 
     { 
     } 

     public virtual void SetSession(ISession session) 
     { 
     } 

     public SqlString OnPrepareStatement(SqlString sql) 
     { 
      ///Do something fancy here like 
      ///sql.Replace("_MonTranTable_", MonthName + "Tran"); 
      return sql; 
     } 
    } 
} 
0

Esta no es una respuesta directa a su pregunta, pero tal vez puede ser una solución después de todo.

¿Quizás pueda agregar una o dos vistas al DB que harán que todas esas tablas dinámicas se vean como una sola?

+0

Pero esas tablas no son fijas ya que dije "Dinámico" así que necesito un poco de lógica del código en sí ... Por el momento puedo para obtener mi solución deseada Lo estoy refinando aún más y actualizaré el progreso –

2

Tuve exactamente el mismo problema y mi enfoque fue actualizar los valores de configuración de NHibernate en tiempo de ejecución. De esta forma, podría decidir cuál de mis muchas tablas de nombre idéntico hablaría. La base de la técnica es la siguiente: -

private static void SetTableMapping(Configuration config, 
    Type persistentClass, string newTableName) 
{ 
    PersistentClass classMapping = config.GetClassMapping(persistentClass); 
    Table physicalTable = classMapping.RootTable; 
    physicalTable.Name = newTableName; 
} 
1
public class NHibernateHelper 
{  
    private static ISessionFactory _sessionFactory; 

    private static ISessionFactory SessionFactory 
    { 
     get 
     { 
      if (_sessionFactory == null) 
      { 
       Configuration configuration = new Configuration(); 
       configuration.Configure(); 

      // configuration.AddAssembly(typeof(clsDocumentMaster).Assembly); 
       configuration.SetNamingStrategy(new MyClass()); 
       configuration.AddFile("clsDocumentMaster.hbm.xml"); 
       //configuration.AddFile("Level15.hbm.xml"); 

       _sessionFactory = configuration.BuildSessionFactory(); 
      } 
      return _sessionFactory; 
     } 
    } 
    public static ISession OpenSession() 
    { 
     return SessionFactory.OpenSession(); 
    } 
} 

public class MyClass : INamingStrategy 
{ 
    #region INamingStrategy Members 

    public string ClassToTableName(string className) 
    { 
     return DefaultNamingStrategy.Instance.ClassToTableName(className); 
    } 

    public string ColumnName(string columnName) 
    { 
     return DefaultNamingStrategy.Instance.ColumnName(columnName); 
    } 

    public string LogicalColumnName(string columnName, string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.LogicalColumnName(columnName, propertyName); 
    } 

    public string PropertyToColumnName(string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.PropertyToColumnName(propertyName); 
    } 

    public string PropertyToTableName(string className, string propertyName) 
    { 
     return DefaultNamingStrategy.Instance.PropertyToTableName(className, propertyName); 
    } 

    public string TableName(string tableName) 
    { 
     if (tableName.IndexOf("[TagtableName]") > -1) 
      tableName = tableName.Replace("[TagtableName]", "TAG1"); 
     else 
      tableName = DefaultNamingStrategy.Instance.TableName(tableName); 

     return DefaultNamingStrategy.Instance.TableName(tableName); 

    } 

    #endregion 
} 
Cuestiones relacionadas