2009-08-21 15 views
11

Stiamo progettando un prodotto in grado di supportare più database. Stiamo facendo qualcosa di simile al momento in modo che il nostro codice supporta MS SQL e MySQL:Qual è il modo migliore per supportare più database per un prodotto .NET?

namespace Handlers 
{ 
    public class BaseHandler 
    { 
     protected string connectionString; 
     protected string providerName; 

     protected BaseHandler() 
     { 
      connectionString = ApplicationConstants.DatabaseVariables.GetConnectionString(); 
      providerName = ApplicationConstants.DatabaseVariables.GetProviderName(); 
     } 
    } 
} 

namespace Constants 
{ 
    internal class ApplicationConstants 
    { 
     public class DatabaseVariables 
     { 
      public static readonly string SqlServerProvider = "System.Data.SqlClient"; 
      public static readonly string MySqlProvider = "MySql.Data.MySqlClient"; 

      public static string GetConnectionString() 
      { 
       return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ConnectionString; 
      } 

      public static string GetProviderName() 
      { 
       return ConfigurationManager.ConnectionStrings["CONNECTION_STRING"].ProviderName; 
      } 
     } 
    } 
} 

namespace Handlers 
{ 
    internal class InfoHandler : BaseHandler 
    { 
     public InfoHandler() : base() 
     { 
     } 

     public void Insert(InfoModel infoModel) 
     { 
      CommonUtilities commonUtilities = new CommonUtilities(); 
      string cmdInsert = InfoQueryHelper.InsertQuery(providerName); 
      DbCommand cmd = null; 
      try 
      { 
       DbProviderFactory provider = DbProviderFactories.GetFactory(providerName); 
       DbConnection con = LicDbConnectionScope.Current.GetOpenConnection(provider, connectionString); 
       cmd = commonUtilities.GetCommand(provider, con, cmdInsert); 
       commonUtilities.PrepareCommand(cmd, infoModel.AccessKey, "paramAccessKey", DbType.String, false, provider, providerName); 
       commonUtilities.PrepareCommand(cmd, infoModel.AccessValue, "paramAccessValue", DbType.String, false, provider, providerName); 
       cmd.ExecuteNonQuery(); 
      } 
      catch (SqlException dbException) 
      { 
       //-2146232060 for MS SQL Server 
       //-2147467259 for MY SQL Server 
       /*Check if Sql server instance is running or not*/ 
       if (dbException.ErrorCode == -2146232060 || dbException.ErrorCode == -2147467259) 
       { 
        throw new BusinessException("ER0008"); 
       } 
       else 
       { 
        throw new BusinessException("GENERIC_EXCEPTION_ERROR"); 
       } 
      } 
      catch (Exception generalException) 
      { 
       throw generalException; 
      } 
      finally 
      { 
       cmd.Dispose(); 
      } 
     } 
    } 
} 

namespace QueryHelpers 
{ 
    internal class InfoQueryHelper 
    { 
     public static string InsertQuery(string providerName) 
     { 
      if (providerName == ApplicationConstants.DatabaseVariables.SqlServerProvider) 
      { 
       return @"INSERT INTO table1 
      (ACCESS_KEY 
      ,ACCESS_VALUE) 
    VALUES 
      (@paramAccessKey 
      ,@paramAccessValue) "; 
      } 
      else if (providerName == ApplicationConstants.DatabaseVariables.MySqlProvider) 
      { 
       return @"INSERT INTO table1 
      (ACCESS_KEY 
      ,ACCESS_VALUE) 
    VALUES 
      (?paramAccessKey 
      ,?paramAccessValue) "; 
      } 
      else 
      { 
       return string.Empty; 
      } 
     } 
    } 
} 

Potete suggerire prego se c'è un modo migliore di farlo? Inoltre quali sono i pro e i contro dell'approccio?

+2

Suggerisco di suddividere il codice in diversi blocchi per semplificare la lettura.Così com'è, c'è un sacco di codice overflow del margine destro e c'è solo una barra di scorrimento orizzontale verso il basso verso la fine del codice. –

risposta

2

per la vostra attuale necessità, sono d'accordo con NHibernate ...

voglio solo far notare qualcosa con la gerarchia di classe ...

sarete meglio usare l'interfaccia

piace (Basta controllare il documento o Internet per la sintassi esatta)

Interface IDBParser 
    Function1 
    Function2 

class MSSQLParser : IDBParser 
    Function1 
    Function2 

class MySQLParser : IDBParser 
    Function1 
    Function2 

Poi nel codice è possibile utilizzare l'interfaccia di

Main() 
    IDBParser dbParser; 
    if(...) 
     dbParser = new MSSQLParser(); 
    else 
     dbParser = new MySQLParser(); 

    SomeFunction(dbParser); 

// the parser can be sent by parameter, global setting, central module, ... 
    SomeFunction(IDBParser dbParser) 
     dbParser.Function1(); 

In questo modo sarà più facile da gestire e il codice non sarà pieno dello stesso se la condizione/altro. Sarà anche molto più facile aggiungere altri DB. Un altro vantaggio è che potrebbe aiutarti a testare le unità inviando un oggetto fittizio.

+0

Mi è piaciuto questo approccio – Kalpak

1

Esistono livelli di mappatura relazionale degli oggetti che supporteranno più tecnologie di database, come Entity Spaces.

10

Qualunque cosa tu faccia, non mi scrivere il proprio codice di mappatura. È già stato fatto prima, e probabilmente è stato fatto un milione di volte meglio di qualunque cosa si possa scrivere a mano.

Senza dubbio, è necessario utilizzare NHibernate. È un mapper object-relational che rende trasparente l'accesso al database: si definisce un set di classi DAL che rappresentano ciascuna tabella nel proprio database e si utilizzano i provider NHibernate per eseguire query sul database. NHibernate genererà dinamicamente l'SQL richiesto per interrogare il database e popolare gli oggetti DAL.

La cosa bella di NHibernate è che genera SQL in base a qualsiasi cosa tu abbia specificato nel file di configurazione. Pronto per l'uso supporta SQL Server, Oracle, MySQL, Firebird, PostGres e a few other databases.

+0

Neanche l'1% ha dubbi? – MusiGenesis

+0

Dal dubbio Juliet

0

Un approccio a questo problema consiste nel progettare l'applicazione in modo che funzioni completamente con DataSet disconnessi e scrivere un componente di accesso ai dati che gestisca il recupero dei dati dalle diverse marche di database che verranno supportate, nonché le modifiche persistenti apportate al DataSet dall'applicazione torna ai database originali.

Pro: DataSet in .Net sono ben scritti, facili da usare e potenti, e fanno un ottimo lavoro di fornire metodi e strumenti per lavorare con i dati basati su tabella.

Contro: Questo metodo può essere problematico se l'applicazione deve funzionare con insiemi di dati estremamente grandi sul lato client.

1

In questi casi, ciò che è sempre buono è creare un'architettura a livelli, in cui tutti gli elementi correlati a DB siano SOLO nel livello di accesso ai dati. Quindi potresti avere diverse implementazioni del tuo livello DAO, uno per Oracle, SQL Server, ecc ...

Devi separare il livello aziendale dal livello DAO con le interfacce, in modo che il tuo livello aziendale li usi per accedere al DAO strato. In questo modo è possibile scambiare perfettamente l'implementazione di sottostringa del livello DAO per l'esecuzione su un DB Oracle o qualsiasi altro sistema.

Un altro buon suggerimento è quello di dare un'occhiata a mappatori oggetto-relazionali come Scott già suggerito. Darei un'occhiata al framework NHibernate o Entity.

0

In questo momento, Entity Framework di Microsoft ha alcune funzioni, alcune delle quali possono essere interrotte, a seconda dell'architettura prevista dell'applicazione.

Da quello che ho visto e letto su V2, che verrà spedito con .Net 4, penso che meriterà certamente di essere visto.

0

Molte persone hanno suggerito un framework di mappatura O/R come NHibernate. Questo è un approccio abbastanza ragionevole a meno che tu non voglia usare un mappatore O/R per qualche ragione. Qualcosa come NHibernate probabilmente ti farà guadagnare il 95% + ma potresti dover scrivere qualche SQL personalizzato. Non fatevi prendere dal panico se questo è il caso; puoi ancora fare una soluzione ad hoc per il resto.

In questo caso, prendere i bit che richiedono l'SQL personalizzato e separarli in un modulo di plugin specifico per piattaforma. Scrivi i plugin Oracle, MySQL, SQL Server (ecc.) Come necessario per le singole piattaforme di database che vuoi supportare.

ADO.Net rende abbastanza semplice il wrapping di sproc, quindi è possibile spostare lo strato dipendente dalla piattaforma in alcune stored procedure, presentando un'API consitente più o meno al livello intermedio. Ci sono ancora alcune dipendenze dalla piattaforma (come il prefisso '@' sui nomi delle variabili di SQL Server), quindi è necessario creare un meccanismo generico di wrapper sproc (che non è poi così difficile).

Con un po 'di fortuna, le operazioni specifiche che voi hanno bisogno di per scoppiare in questo modo saranno abbastanza piccole in numero quindi la quantità di lavoro per mantenere i plug-in sarà limitata.

2

Se è necessario codificarlo autonomamente e non utilizzare un prodotto che fornisce accesso unificato, ricordare che oggetti come SqlDataAdapter e OracleDataAdapter ereditano dal comune DbDataAdapter (almeno nelle versioni successive del runtime). Se si esegue il downdown su DbDataAdapter, è possibile scrivere codice che funzionerà con entrambi i database nelle posizioni in cui si farebbe lo stesso per entrambi i database. Alcuni del vostro codice sarà un po 'come questo:

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter; 

Una volta fuso verso il basso, non importa se si tratta di uno SqlDataAdapter o un OracleDataAdapter. Puoi chiamarlo allo stesso modo.

Tuttavia, è importante ricordare che la codifica di due database implica l'utilizzo di funzionalità che esistono solo all'interno di entrambi, pur dovendo ovviare alle carenze di entrambe. Non è davvero una buona idea.

2

Se è necessario un mapping dalle voci del database agli oggetti, suggerisco di utilizzare la soluzione già suggerita: NHibernate. Se questo sembra eccessivo per la tua applicazione e vuoi seguire l'approccio di Ado.net e non hai bisogno di un'animazione O/RM, dovresti dare un'occhiata a ciò che i ragazzi di Spring.net hanno fatto e conoscere lo Ado.Net Provider Abstraction.

Problemi correlati