开发自己的Data Access Application Block[上篇]
经常在网上看到对ORM的讨论沸沸扬扬,我也来凑个热闹,谈谈我写的一个ORM。最近在做一项工作,把我们经常用到的一些业务逻辑抽象出来,写成一个个的Application Block,使之可以运用到不同的Application中,比如Data Access,Messaging,Auditing,Data bind
经常在网上看到对ORM的讨论沸沸扬扬,我也来凑个热闹,谈谈我写的一个ORM。最近在做一项工作,把我们经常用到的一些业务逻辑抽象出来,写成一个个的Application Block,使之可以运用到不同的Application中,比如Data Access,Messaging,Auditing,Data binding等等。现在先做一个Data access application block。由于时间仓促,没有进行什么优化和较多的测试,大家不必深究我所提供的Code ,我只希望为大家的ORM提供另一种想法。这个application block应达到的目的:
-
封装所有的Data Access操作。
-
适合主流的DBMS:SQL Server(2000和2005),Oracle(9i和10g),DB2。
-
尽量简化Developer的操作和提供最大的灵活性,在Data Retrieval方面,只要指定SQL或者Stored Procedure和相应的参数;在Data Update方面,既可以直接调用SQL和Stored Procedure,还可以把包含多个相互关联Data Table的Dataset通过一次调用实现数据的更新。此外,可以自由地选择使用SQL还是Stored procedure;可以使用Commander builder生成Command或者使用基于Mapped stored procedure生成的Command进行数据更新。
-
实现泛型编程,使使用该AppBlock的代码能够适合所有的数据库。
-
实现Transaction。
-
提供可配置性,包括不同数据库的配置,不同Data Mapping的配置等等。
下面是该AppBlock使用到的Entity:
-
Database:Abstract Class,封装了绝大部分和具体数据库无关的Data Access操作逻辑。通过两个Mapping:IDbParameterNameMapping和IStoredProcedureNameMapping,实现Dataset和Db的一个映射。比如Dataset中Data table name和Stored procedure name的Mapping,Data table中Field和Stored procedure中参数名的Mapping。这两个Mapping是可以配置的,你只需要实现提供的Interface编写适合你的Mapping provider就可以了。
-
SqlDatabase:封装基于SQL Server 的操作。ADO.NET 2.0在1.0的基础上作了很大的改善,主要的增加的大量的基类,为我们进行泛型编程,编写和具体Db无关的代码变得异常容易。所以我们把大多数Data Access的操作可以封装在Abstract Database类中,SqlDatabase中的内容实际上是很少的。
-
OracleDatabase:封装基于Oracle的操作。
-
IDbParameterNameMapping和IStoredProcedureNameMapping:我想大家都是这样的感受,实现ORM的本质就是实现内存中的数据(主要是Dataset)和数据库的一个映射。在Dataset和数据库中的Table相互Mapping方面,我觉得没有必要采用特殊的Mapping,直接和简单易行的就是Table和Dataset中的Data Table完全匹配(table name 和field name完全匹配)。所以重要的是实现Dataset和Stored procedure的Mapping:Table Name如何与进行Insert,Update,Delete的Stored procedure name匹配,不同Version(original & current)的Field如何与Stored procedure的Parameter name 匹配。而这样一个匹配应该是可配置的,因为每个Application在数据库设计时的命名都有各自的要求,所以我在这里采用的Provider的设计模式。用户可以实现这两个Interface编写适合自己的Mapping provider,通过我提供的Configuration block很容易地完成配置。同时,我写了一个默认的,简单的Mapping:SimpleDbParameterNameMapping和SimpleStoredProcedureNameMapping。
有一点需要补充的是,要实现上面的Mapping,对Stored Procedure的命名有较高的要求,手工编写的方式已经不能适合我们的要求,所以我们需要一个生成Stored procedure的Generator,这个Generator也使用这两个可配置的Mapping接口。
-
DatabaseFactory: 一个静态的类,根据配置的信息创建你需要的具体的Database对象,实现泛型化编程。
-
DataAccessConfigurationCollection,DataAccessConfigurationElement,DataAccessConfigurationdiv 三个Configuration的Class。
为了使大家清楚地看出这个Application block所有的操作,我把所有的操作封装在一个IDatabase的interface中,不过需要注意的是,我采用的是基于Abstract class的编程,而不是基于Interface的编程,相信大家对这两种方式讨论得已经碰倒的太多了,孰优孰劣我就不想对说了。这个IDatabase 接口,只是展示所有Operation之用,并没有在我的代码中用到。
namespace Artech.ApplicationBlock.DataAccess
{
public interface IDatabase
{
Fill a System.Data.DataSet with retrieved data.#region Fill a System.Data.DataSet with retrieved data.
void FillDataSet(DataSet dataInfo, string commandText, IDictionarystring, object> parameters);
void FillDataSet(DataSet dataInfo, string tableName, string commandText, IDictionarystring, object> parameters);
void FillDataSet(DataSet dataInfo, string tableName, CommandType commandType, string commandText, IDictionarystring, object> parameters);
#endregion
Save the changed data which is stored in a dataset into database.#region Save the changed data which is stored in a dataset into database.
void UpdateData(DataSet dataInfo);
void UpdateData(DataTable table);
void UpdateData(DataTable table, string insertCommandText, string updateCommandText, string deleteCommandText,
Dictionarystring, object> insertParameters, Dictionarystring, object> updateParameters, Dictionarystring, object> deleteParameters);
void UpdateData(DataTable table, CommandType commandType, string insertCommandText, string updateCommandText, string deleteCommandText,
Dictionarystring, object> insertParameters, Dictionarystring, object> updateParameters, Dictionarystring, object> deleteParameters);
void UpdateData(DataTable table, DbCommand insertCommand, DbCommand updateCommand, DbCommand deleteCommand);
#endregion
Execute a command and return the affect row count.#region Execute a command and return the affect row count.
int ExecuteNonQuery(CommandType commandType, string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
int ExecuteNonQuery(CommandType commandType, string commandText, Dictionarystring, object> inputParameters);
int ExecuteNonQuery( string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
int ExecuteNonQuery( string commandText, Dictionarystring, object> inputParameters);
#endregion
Execute a command and return the data in the form of data reader.#region Execute a command and return the data in the form of data reader.
DbDataReader ExecuteReader(CommandType commandType, string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
DbDataReader ExecuteReader(CommandType commandType, string commandText, Dictionarystring, object> inputParameters);
DbDataReader ExecuteReader(string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
DbDataReader ExecuteReader(string commandText, Dictionarystring, object> inputParameters);
#endregion
Execute a command and return a scalar value.#region Execute a command and return a scalar value.
object ExecuteScalar(CommandType commandType, string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
object ExecuteScalar(CommandType commandType, string commandText, Dictionarystring, object> inputParameters);
object ExecuteScalar(string commandText, Dictionarystring, object> inputParameters, Dictionarystring, object> outputParameters);
object ExecuteScalar(string commandText, Dictionarystring, object> inputParameters);
#endregion
Transaction based operation#region Transaction based operation
void BeginTransaction();
void Commit();
void RollBack();
#endregion
}
}
这个列表和大部分ORM没有什么太大的区别,大家已经司空见惯,实现起来也不会有什么太大的困难。对于大部分操作,我不会做详细的介绍。接下来我们来简要地看看这样一个AppBlock是如何实现的。
1. Data Mapping
我们首先来看看Data Mapping:实现Dataset中Table name和Stored Procedure Name的Mapping,以及Dataset 中的Field 和Stored procedure的参Parameter name的Mapping。
IDbParameterNameMapping
using System;
using System.Collections.Generic;
using System.Text;
namespace Artech.ApplicationBlock.DataMapping
{
/**////
/// IStoredProcedureNameMapping defines the mapping between the data table name and the name of stored procedures to perform insertion, modification and deletion operation.
///
public interface IStoredProcedureNameMapping
{
/**////
/// Get the name of stored procedure to perform seletion operation.
///
/// The name of the database table.
///
string GetSelectStoredProcedureName(string tableName);
/**////
/// Get the name of stored procedure to perform insert operation.
///
/// The name of the database table.
///
string GetInsertStoredProcedureName(string tableName);
/**////
/// Get the name of stored procedure to perform modification operation.
///
/// The name of the database table.
///
string GetModifyStoredProcedureName(string tableName);
/**////
/// Get the name of stored procedure to perform deletion operation.
///
/// The name of the database table.
///
string GetDeleteStoredProcedureName(string tableName);
}
}
IDbParameterNameMapping
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace Artech.ApplicationBlock.DataMapping
{
/**////
/// IDbParameterNameMapping define the defult mapping between the source column name and the parameter name of the corresponding stored procedure.
///
public interface IDbParameterNameMapping
{
/**////
/// Get the source column name based on the parameter name of the related stored procedure.
///
/// The parameter name of the corresponding stored procedure.
///
string GetSourceCoulmnName(string patameterName);
/**////
/// Get the source parameter name based on the source column name.
///
/// The source column name corresponding to the parameter name.
/// The data row version of the source solumn conressponding to the parameter.
///
string GetParameterName(string columnName, DataRowVersion rowVersion);
}
}
这两个Mapping主要用在通过Dataset跟新数据库的场景,利用IDbParameterNameMapping,我们通过Dataset中各个Table name获得对它进行Insert,Update,Delete操作的Stored procedure的name。利用IDbParameterNameMapping,我们可以为Stored procedure的Parameter指定对应的Source field.
注:GetParameterName方法实际上是不需要的,我把使用在另一个AppBlock中。
接下来我们来写两个实现了上面连个Interface的默认的mapping:SimpleStoredProcedureNameMapping和SimpleDbParameterNameMapping。他实际上实现了这样的Mapping:比如Table name为T_ABC_DEF(我经常用的命名方式:以T开头代表Table,名称大写并一下划线连接),那么对应的Stored procedure name分别为:sp_abc_def_s(Select), sp_abc_def_i(Insert), sp_abc_def_u(Update), sp_abc_def_d(delete)。如果Field name为ABC_123,那么对于Original version的Parameter name为o_abc_123(o代表Original),Current version的Parameter name为p_abc_123(p代表一般意义的Parameter)。
using System;
using System.Collections.Generic;
using System.Text;
namespace Artech.ApplicationBlock.DataMapping
{
/**////
/// IStoredProcedureNameMapping defines the mapping between the data table name and the name of stored procedures to perform insertion, modification and deletion operation.
///
public class SimpleStoredProcedureNameMapping:IStoredProcedureNameMapping
{

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











1. Windows 11で設定を開きます。 Win+I ショートカットまたはその他の方法を使用できます。 2. 「アプリ」セクションに移動し、「アプリと機能」をクリックします。 3. バックグラウンドでの実行を禁止したいアプリケーションを見つけます。三点ボタンをクリックして、[詳細オプション] を選択します。 4. [バックグラウンド アプリケーションのアクセス許可] セクションを見つけて、目的の値を選択します。デフォルトでは、Windows 11 は電力最適化モードを設定します。これにより、Windows はアプリケーションがバックグラウンドでどのように動作するかを管理できるようになります。たとえば、バッテリーを節約するためにバッテリー セーバー モードを有効にすると、システムはすべてのアプリを自動的に終了します。 5. アプリケーションがバックグラウンドで実行されないようにするには、[なし] を選択します。プログラムが通知を送信していない、データの更新に失敗しているなどに気付いた場合は、次のことができることに注意してください。

この AI 支援プログラミング ツールは、急速な AI 開発のこの段階において、多数の有用な AI 支援プログラミング ツールを発掘しました。 AI 支援プログラミング ツールは、開発効率を向上させ、コードの品質を向上させ、バグ率を減らすことができます。これらは、現代のソフトウェア開発プロセスにおける重要なアシスタントです。今日は Dayao が 4 つの AI 支援プログラミング ツールを紹介します (すべて C# 言語をサポートしています)。皆さんのお役に立てれば幸いです。 https://github.com/YSGStudyHards/DotNetGuide1.GitHubCopilotGitHubCopilot は、より少ない労力でより迅速にコードを作成できるようにする AI コーディング アシスタントであり、問題解決とコラボレーションにより集中できるようになります。ギット

DeepSeekはファイルを直接PDFに変換できません。ファイルの種類に応じて、異なる方法を使用できます。一般的なドキュメント(Word、Excel、PowerPoint):Microsoft Office、Libreoffice、その他のソフトウェアを使用してPDFとしてエクスポートします。画像:画像ビューアまたは画像処理ソフトウェアを使用してPDFとして保存します。 Webページ:ブラウザの「Print into PDF」関数を使用するか、PDFツールに専用のWebページを使用します。 UNCOMMONフォーマット:適切なコンバーターを見つけて、PDFに変換します。適切なツールを選択し、実際の状況に基づいて計画を作成することが重要です。

アプリを使用しようとすると、「カメラとマイクへのアクセスを許可できません」というメッセージが表示されますか?通常、カメラとマイクのアクセス許可は、必要に応じて特定の人に付与します。ただし、許可を拒否すると、カメラとマイクは機能しなくなり、代わりにこのエラー メッセージが表示されます。この問題の解決は非常に基本的なもので、1 ~ 2 分で解決できます。解決策 1 – カメラ、マイクの権限を提供する 必要なカメラとマイクの権限を設定で直接提供できます。ステップ 1 – [設定] タブに移動します。ステップ 2 – [プライバシーとセキュリティ] パネルを開きます。ステップ 3 – そこで「カメラ」権限をオンにします。ステップ 4 – 内部には、携帯電話のカメラの許可を要求したアプリのリストが表示されます。ステップ5 – 指定したアプリの「カメラ」を開きます

Java の DAO (Data Access Object) は、アプリケーション コードと永続層を分離するために使用されます。その利点は次のとおりです。 分離: アプリケーション ロジックから独立しているため、変更が容易になります。カプセル化: データベース アクセスの詳細を非表示にし、データベースとの対話を簡素化します。スケーラビリティ: 新しいデータベースや永続化テクノロジをサポートするために簡単に拡張できます。 DAO を使用すると、アプリケーションはデータベースの詳細を直接処理することなく、メソッドを呼び出してエンティティの作成、読み取り、更新、削除などのデータベース操作を実行できます。

Java では、「フィールド」は、データまたは状態を格納するために使用されるクラスまたはインターフェイスのデータ メンバーです。フィールドのプロパティには、タイプ (任意の Java データ型)、アクセス権、静的 (インスタンスではなくクラスに属する)、最終 (不変)、および一時 (シリアル化されていない) が含まれます。フィールドは、オブジェクト データの保存やオブジェクトの状態の維持など、クラスまたはインターフェイスの状態情報を保存するために使用されます。

Java リフレクション メカニズムを使用すると、プログラムはソース コードを変更せずにクラスの動作を動的に変更できます。 Class オブジェクトを操作することで、newInstance() によるインスタンスの作成、プライベート フィールドの値の変更、プライベート メソッドの呼び出しなどが可能になります。ただし、リフレクションは予期しない動作やセキュリティ上の問題を引き起こす可能性があり、パフォーマンスのオーバーヘッドがあるため、注意して使用する必要があります。

Vue で iframe クロスドメインの問題を解決する方法: CORS: バックエンド サーバーで CORS サポートを有効にし、XMLHttpRequest またはフェッチ API を使用して Vue で CORS リクエストを送信します。 JSONP: バックエンド サーバーの JSONP エンドポイントを使用して、Vue に JSONP スクリプトを動的に読み込みます。プロキシ サーバー: リクエストを転送するためにプロキシ サーバーを設定し、Vue のサードパーティ ライブラリ (axios など) を使用してリクエストを送信し、プロキシ サーバー URL を設定します。
