12

複数のデータベースをサポートできる製品を設計しています。現在、コードが MySQL だけでなく MS SQL もサポートするように、次のようなことを行っています。

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

何か良い方法があれば教えていただけないでしょうか。また、アプローチの長所と短所は何ですか?

4

10 に答える 10

10

何をするにしても、独自のマッピング コードを記述しないでください。それはすでに以前に行われており、おそらく、手書きで書くよりも 100 万倍優れた方法で行われています。

間違いなく、NHibernateを使用する必要があります。データベース アクセスを透過的にするオブジェクト リレーショナル マッパーです。データベース内の各テーブルを表す一連の DAL クラスを定義し、NHibernate プロバイダーを使用してデータベースに対してクエリを実行します。NHibernate は、データベースにクエリを実行し、DAL オブジェクトを設定するために必要な SQL を動的に生成します。

NHibernate の優れた点は、構成ファイルで指定した内容に基づいて SQL を生成することです。そのままで、SQL Server、Oracle、MySQL、Firebird、PostGres、およびその他のいくつかのデータベースをサポートします。

于 2009-08-21T12:19:54.767 に答える
5

私はNHibernateを使用します。

ここに素晴らしい初心者向けチュートリアルがあります

于 2009-08-21T12:19:25.313 に答える
3

あなたの現在のニーズについては、NHibernateに同意します...

クラス階層で何かを指摘したいだけです...

インターフェイスを使用することをお勧めします

いいね(正確な構文については、ドキュメントまたはインターネットを確認してください)

Interface IDBParser  
    Function1  
    Function2  

class MSSQLParser : IDBParser  
    Function1  
    Function2  

class MySQLParser : IDBParser  
    Function1  
    Function2 

次に、コードでインターフェイスを使用できます

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

そうすれば、管理が容易になり、コードが同じ if/else 条件でいっぱいになることはありません。また、他のDBを追加するのもずっと簡単になります。もう 1 つの利点は、モック オブジェクトを送信することで単体テストに役立つことです。

于 2009-08-22T15:42:22.540 に答える
2

自分でコーディングする必要があり、統合アクセスを提供する製品を使用しない場合は、SqlDataAdapter や OracleDataAdapter などのオブジェクトが共通の DbDataAdapter を継承することを覚えておいてください (少なくともランタイムの以降のバージョンでは)。DbDataAdapter にキャストすると、両方のデータベースで同じことを行う場所に、両方のデータベースで動作するコードを記述できます。コードの一部は次のようになります。

DbDataAdapter adapter = GetOracleDataAdapter() as DbDataAdapter;

キャストダウンしたら、それが SqlDataAdapter か OracleDataAdapter かは関係ありません。同じように呼び出すことができます。

ただし、2 つのデータベースのコーディングは、両方のデータベースにしか存在しない機能を使用する一方で、両方の欠点を回避する必要があることを覚えておいてください。それは本当に良い考えではありません。

于 2009-08-21T13:14:29.963 に答える
2

データベース エントリからオブジェクトへのマッピングが必要な場合は、既に提案されているソリューションである NHibernate を使用することをお勧めします。これがアプリケーションにとってやり過ぎのように思われ、Ado.net アプローチを使用したいが O/RM ソリューションは必要ない場合は、Spring.net 担当者が行ったことを見て、Ado.Net について学ぶ必要があります。プロバイダーの抽象化。

于 2009-08-21T13:25:00.840 に答える
1

Entity Spacesなど、複数のデータベース テクノロジをサポートするオブジェクト リレーショナル マッピング レイヤーがあります。

于 2009-08-21T12:16:32.830 に答える
1

多くの人が、NHibernate などの O/R マッピング フレームワークを提案しています。何らかの理由で O/R マッパーを使用したくない場合を除き、これは非常に合理的なアプローチです。NHibernate のようなものを使用すると、おそらく 95% 以上はうまくいくでしょうが、カスタム SQL を書く必要があるかもしれません。その場合でも慌てる必要はありません。残りのアドホック ソリューションを実行することもできます。

この場合、カスタム SQL が必要なビットを取り出して、プラットフォーム固有のプラグイン モジュールに分離します。サポートする個々のデータベース プラットフォームの必要に応じて、Oracle、MySQL、SQL Server (など) のプラグインを記述します。

ADO.Net を使用すると、sproc を簡単にラップできるため、プラットフォームに依存するレイヤーをいくつかのストアド プロシージャに移動して、多少一貫性のある API を中間層に提示できる場合があります。いくつかのプラットフォームの依存関係 (SQL Server 変数名の '@' プレフィックスなど) がまだあるため、一般的な sproc ラッパー メカニズムを作成する必要があります (これはそれほど難しいことではありません)。

運が良ければ、この方法でブレークアウトする必要がある特定の操作の数はかなり少ないため、プラグインを維持するための作業量は制限されます。

于 2009-08-21T13:07:27.687 に答える
1

そのような場合に常に良いのは、階層化されたアーキテクチャを作成することです.DB関連のものはすべてデータアクセス層にあるだけです. 次に、DAOレイヤーのさまざまな実装、Oracle、SQL Serverなど用のものを使用できます...

ビジネス層がインターフェイスを使用して DAO 層にアクセスするように、ビジネス層を DAO 層からインターフェイスで分離する必要があります。そのため、DAO レイヤーの基盤となる実装を完全に交換して、Oracle DB または任意のシステムで実行することができます。

もう 1 つの良い提案は、Scott が既に提案したようなオブジェクト リレーショナル マッパーを調べることです。NHibernate または Entity フレームワークを見てみたいと思います。

于 2009-08-21T12:21:10.400 に答える
0

この問題へのアプローチの 1 つは、切断された DataSet で完全に動作するようにアプリケーションを設計し、サポートするさまざまなデータベース ブランドからのデータのフェッチを処理するデータ アクセス コンポーネントを作成し、アプリケーションによって DataSet に加えられた変更を永続化することです。元のデータベースに戻ります。

長所: .Net の DataSet は、適切に作成され、使いやすく、強力であり、テーブルベースのデータを操作するためのメソッドとツールを提供する優れた機能を果たします。

短所: アプリケーションがクライアント側で非常に大きなデータ セットを処理する必要がある場合、この方法は問題になる可能性があります。

于 2009-08-21T12:20:10.027 に答える
0

現在、Microsoft の Entity Framework にはいくつかの欠点があり、アプリケーションの意図するアーキテクチャによっては、契約を破ることができるものもあります。

.Net 4 に同梱される V2 について私が見たり読んだりしたことから、それは確かに注目に値すると思います。

于 2009-08-21T12:23:59.543 に答える