Question

Nous concevons un produit qui pourrait prendre en charge plusieurs bases de données. Nous faisons quelque chose comme actuellement pour que notre code est compatible avec MS SQL ainsi que MySQL:

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

Pouvez-vous s'il vous plaît suggérer s'il y a une façon de le faire mieux? En outre, quels sont les avantages et les inconvénients de l'approche?

Était-ce utile?

La solution

Pour vos besoins actuels, je suis d'accord avec NHibernate ...

Je veux juste signaler quelque chose avec votre hiérarchie de classes ...

Vous mieux utiliser Interface

Comme (Il suffit de consulter la doc ou Internet pour la syntaxe exacte)

Interface IDBParser  
    Function1  
    Function2  

class MSSQLParser : IDBParser  
    Function1  
    Function2  

class MySQLParser : IDBParser  
    Function1  
    Function2 

Ensuite, dans votre code, vous pouvez utiliser l'interface

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

De cette façon, il sera plus facile de gérer et de votre code ne sera pas plein du même if / else condition. Il sera aussi beaucoup plus facile d'ajouter d'autres DB. Un autre avantage est que cela pourrait vous aider à tester l'unité en envoyant objet fantaisie.

Autres conseils

Quoi que vous fassiez, ne pas écrire votre propre code de mappage. Son déjà été fait avant, et son probablement été fait un million de fois mieux que ce que vous pouvez écrire à la main.

Sans aucun doute, vous devez utiliser NHibernate . Son un mappeur objet-relationnel qui fait transparent l'accès base de données: vous définissez un ensemble de classes DAL qui représentent chaque table dans votre base de données et que vous utilisez les fournisseurs NHibernate pour effectuer des requêtes sur la base de données. NHibernate va générer dynamiquement le SQL requis pour interroger la base de données et remplir vos objets DAL.

La bonne chose à propos NHibernate est qu'il génère SQL basé sur ce que vous avez spécifié dans le fichier de configuration. Hors de la boîte, il prend en charge SQL Server, Oracle, MySQL, Firebird, Postgres et quelques autres bases de données .

J'utilise NHibernate .

Voici agréable débutant tutoriel

Si vous devez coder vous-même et ne pas utiliser un produit qui offre un accès unifié, rappelez-vous que les objets comme SqlDataAdapter et OracleDataAdapter héritent de la DbDataAdapter commune (au moins dans les versions ultérieures du moteur d'exécution). Si vous entraînes vers DbDataAdapter, vous pouvez écrire du code qui fonctionnera avec les deux bases de données dans les endroits où vous feriez la même chose pour les deux bases de données. Une partie de votre code ressemblera un peu comme ceci:

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

Une fois que vous avez Casted vers le bas, il n'a pas d'importance si elle est un SqlDataAdapter ou un OracleDataAdapter. Vous pouvez appeler cela de la même manière.

Cependant, rappelez-vous que le codage pour deux bases de données consiste à utiliser des fonctionnalités qui existent seulement dans les deux tout en ayant à contourner les lacunes des deux. Ce n'est pas vraiment une bonne idée.

Si vous avez besoin d'une cartographie à partir des entrées de base de données aux objets que je vous suggère d'aller avec la solution autre déjà suggéré: NHibernate. Si cela semble être surpuissant pour votre application et que vous voulez aller avec l'approche Ado.net et ne nécessitent pas un O / RM-soultion, vous devriez jeter un oeil sur ce que les gars ont fait Spring.Net et apprendre davantage sur le Ado.Net Provider Abstraction.

Il y a là des couches de cartographie relationnelle de l'objet qui soutiendra les technologies de bases de données multiples, comme espaces Entité .

Quelle est toujours bon dans ce cas est de créer une architecture en couches, où toutes les choses liées à DB est juste dans la couche d'accès aux données. Ensuite, vous pourriez avoir différentes implémentations de votre couche DAO, un pour Oracle, SQL Server, etc ...

Vous devez séparer la couche métier de la couche DAO avec des interfaces, telles que votre couche d'affaires les utilise juste pour accéder à la couche de DAO. Ainsi, vous pouvez échanger parfaitement la mise en œuvre de la couche sous-jacente de DAO pour fonctionner sur un Oracle DB ou tout autre système que vous souhaitez.

Une autre bonne idée est de jeter un oeil à cartographes objet-relationnel comme Scott a déjà suggéré. Je prendrais un coup d'oeil au cadre NHibernate ou entité.

Une approche à ce problème est de concevoir votre application fonctionne entièrement avec des jeux de données déconnectées et écrire un composant d'accès aux données qui gère les données fetching des différentes marques de base de données, vous soutiendrez, ainsi que les changements persistants apportés aux DataSets par votre application Retour aux bases de données originales.

Plus:. DataSets en .Net sont bien écrits, faciles à utiliser et puissant, et faire un excellent travail de fournir des méthodes et des outils pour travailler avec des données à base de table-

Inconvénients: Cette méthode peut être problématique si votre application a besoin de travailler avec des ensembles de données extrêmement importantes sur le côté client

.

À l'heure actuelle, Entity Framework de Microsoft a quelques shortcommings, certains d'entre eux qui peuvent être deal breakers, selon l'architecture prévue de l'application.

D'après ce que j'ai vu et lu sur V2, qui sera livré avec .Net 4, je pense qu'il méritera certainement d'être regardé.

Beaucoup de gens ont proposé un cadre de mise en correspondance O / R tels que NHibernate. Ceci est tout à fait une approche raisonnable à moins que vous ne voulez pas utiliser un O / R mappeur pour une raison quelconque. Quelque chose comme NHibernate va probablement vous 95% + de la manière, mais vous devrez peut-être écrire quelques SQL personnalisée. Ne paniquez pas si tel est le cas; vous pouvez toujours faire une solution ad hoc pour le reste.

Dans ce cas, prenez les bits qui ont besoin de l'SQL personnalisée et les séparer dans un module de plug-in spécifique de la plate-forme. Ecrire Oracle, MySQL, SQL Server (etc.) plugins que nécessaire pour les plates-formes de bases de données individuelles que vous souhaitez soutenir.

ADO.Net rend assez facile à envelopper sprocs, de sorte que vous pourriez être en mesure de déplacer la couche dépendante de la plate-forme vers le bas dans certaines procédures stockées, présentant une plus ou moins API consitent au niveau intermédiaire. Il y a encore quelques dépendances de la plate-forme (comme le « @ » préfixe sur les noms de variables SQL Server), donc vous devez faire un mécanisme d'emballage sproc générique (qui est pas si difficile).

Avec un peu de chance, les opérations spécifiques que vous besoin pour sortir de cette manière sera assez faible en nombre si la quantité de travail pour maintenir les plug-ins seront limités.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top