I.はじめに
Dapperとは何かについては、ここでは詳しく説明しません。この記事では、.Net CoreでのDapperの使用について簡単に説明します。提示されたコードは主に例に基づいており、単なるガイドです。開発者はそれに応じて拡張および調整できます。自分のニーズに合わせて;抜けがある場合は、お気軽に修正してください。
2.ダッパー環境構築
現在、.Net Core WebAPIまたはMVCプロジェクトを例にとると、フレームワークのバージョンは.NET 5.0であり、関連するNuGetパッケージの参照は次のとおりです。
インストール-パッケージダッパー
インストール-パッケージDapper.Contrib
インストール-パッケージDapper.SqlBuilder
Install-Package System.Data.SqlClient
その中で、Dapper.ContribとDapper.SqlBuilderはDapperの拡張機能です。もちろん、Dapperの拡張機能には、Dapper.Rainbowなどの他のパッケージが含まれており、それぞれのニーズに応じて参照できます。関連する参照については、次のように説明します。
- Dapper:言うまでもありません。
- Dapper.Contrib:オブジェクトを使用して、データテーブルを追加、削除、変更、およびクエリできるため、SQLステートメントを作成する必要がありません。
- Dapper.SqlBuilder:Join、SELECT、Where、OrderByなどのSQLステートメントを動的に作成すると便利です。
- System.Data.SqlClient:サンプルデータベースはMySqlなどのSQL Serverであるため、MySql.Dataを参照してください。
Dapper.Contribエンティティ構成オプションの場合、Productクラスを例にとると、簡単な説明は次のとおりです。
[Table("Product")]
public class Product
{
[Key]
public int Id { get; set; }
public string Name{ get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public DateTime CreateTime { get; set; }
}
エンティティ構成アイテムには、次の主なアイテムがあります。
- テーブル:データベーステーブル名を指定します。これは無視できます。
- キー:自動インクリメントの主キーとして指定されます。
- ExplicitKey:guidなどの自動拡張されない主キーを指定します。
- 計算済み:計算済みの列属性。挿入および更新操作では無視されます。
- 書き込み:書き込み可能かどうか、[Write(false)]などのtrue / false、falseの場合、挿入および更新操作はこの列を無視します。たとえば、拡張可能な部分クラスは、データ表;
データテーブルオブジェクトエンティティの場合、T4テンプレートと組み合わせて生成できます。
3.ダッパーパッケージ
次のようにパッケージを調整するための変更を行います。
DapperDBContextクラスを定義します
コードを表示
コードを表示
上記のコードは、データベースにアクセスするDapperの基本的な操作をカバーしており、同期と非同期に分けられます。これらのほとんどは繰り返されず、次のページング部分に焦点が当てられます。
非同期ページング構造(PageAsync)
ページングの便宜のために、照会するSqlステートメント(SELECT * FROM Table、Order BYを含める必要がありますなど)、ページインデックス、およびページサイズを渡すだけで済みます。
構築方法については、小さなORMツールであるPetaPocoを参照し、次のように関連するコードを抽出してください。興味のある学生は、自分で変換することもできます。
public class Page<T>
{
/// <summary>
/// The current page number contained in this page of result set
/// </summary>
public long CurrentPage { get; set; }
/// <summary>
/// The total number of pages in the full result set
/// </summary>
public long TotalPages { get; set; }
/// <summary>
/// The total number of records in the full result set
/// </summary>
public long TotalItems { get; set; }
/// <summary>
/// The number of items per page
/// </summary>
public long ItemsPerPage { get; set; }
/// <summary>
/// The actual records on this page
/// </summary>
public IEnumerable<T> Items { get; set; }
//public List<T> Items { get; set; }
}
public class DapperPage
{
public static void BuildPageQueries(long skip, long take, string sql, out string sqlCount, out string sqlPage)
{
// Split the SQL
if (!PagingHelper.SplitSQL(sql, out PagingHelper.SQLParts parts))
throw new Exception("Unable to parse SQL statement for paged query");
sqlPage = BuildPageSql.BuildPageQuery(skip, take, parts);
sqlCount = parts.sqlCount;
}
}
static class BuildPageSql
{
public static string BuildPageQuery(long skip, long take, PagingHelper.SQLParts parts)
{
parts.sqlSelectRemoved = PagingHelper.rxOrderBy.Replace(parts.sqlSelectRemoved, "", 1);
if (PagingHelper.rxDistinct.IsMatch(parts.sqlSelectRemoved))
{
parts.sqlSelectRemoved = "peta_inner.* FROM (SELECT " + parts.sqlSelectRemoved + ") peta_inner";
}
var sqlPage = string.Format("SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) peta_rn, {1}) peta_paged WHERE peta_rn>{2} AND peta_rn<={3}",
parts.sqlOrderBy ?? "ORDER BY (SELECT NULL)", parts.sqlSelectRemoved, skip, skip + take);
//args = args.Concat(new object[] { skip, skip + take }).ToArray();
return sqlPage;
}
//SqlServer 2012及以上
public static string BuildPageQuery2(long skip, long take, PagingHelper.SQLParts parts)
{
parts.sqlSelectRemoved = PagingHelper.rxOrderBy.Replace(parts.sqlSelectRemoved, "", 1);
if (PagingHelper.rxDistinct.IsMatch(parts.sqlSelectRemoved))
{
parts.sqlSelectRemoved = "peta_inner.* FROM (SELECT " + parts.sqlSelectRemoved + ") peta_inner";
}
var sqlOrderBy = parts.sqlOrderBy ?? "ORDER BY (SELECT NULL)";
var sqlPage = $"SELECT {parts.sqlSelectRemoved} {sqlOrderBy} OFFSET {skip} ROWS FETCH NEXT {take} ROWS ONLY";
return sqlPage;
}
}
static class PagingHelper
{
public struct SQLParts
{
public string sql;
public string sqlCount;
public string sqlSelectRemoved;
public string sqlOrderBy;
}
public static bool SplitSQL(string sql, out SQLParts parts)
{
parts.sql = sql;
parts.sqlSelectRemoved = null;
parts.sqlCount = null;
parts.sqlOrderBy = null;
// Extract the columns from "SELECT <whatever> FROM"
var m = rxColumns.Match(sql);
if (!m.Success)
return false;
// Save column list and replace with COUNT(*)
Group g = m.Groups[1];
parts.sqlSelectRemoved = sql.Substring(g.Index);
if (rxDistinct.IsMatch(parts.sqlSelectRemoved))
parts.sqlCount = sql.Substring(0, g.Index) + "COUNT(" + m.Groups[1].ToString().Trim() + ") " + sql.Substring(g.Index + g.Length);
else
parts.sqlCount = sql.Substring(0, g.Index) + "COUNT(*) " + sql.Substring(g.Index + g.Length);
// Look for the last "ORDER BY <whatever>" clause not part of a ROW_NUMBER expression
m = rxOrderBy.Match(parts.sqlCount);
if (!m.Success)
{
parts.sqlOrderBy = null;
}
else
{
g = m.Groups[0];
parts.sqlOrderBy = g.ToString();
parts.sqlCount = parts.sqlCount.Substring(0, g.Index) + parts.sqlCount.Substring(g.Index + g.Length);
}
return true;
}
public static Regex rxColumns = new Regex(@"\A\s*SELECT\s+((?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|.)*?)(?<!,\s+)\bFROM\b", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static Regex rxOrderBy = new Regex(@"\bORDER\s+BY\s+(?!.*?(?:\)|\s+)AS\s)(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?(?:\s*,\s*(?:\((?>\((?<depth>)|\)(?<-depth>)|.?)*(?(depth)(?!))\)|[\w\(\)\.])+(?:\s+(?:ASC|DESC))?)*", RegexOptions.RightToLeft | RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
public static Regex rxDistinct = new Regex(@"\ADISTINCT\s", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.Compiled);
}
ページングステートメントを作成する場合の例は、BuildPageQueryとBuildPageQuery2です。前者はROW_NUMBER ( SqlServer2005および2008の場合)を介してページングし、後者はOFFSETおよびFETCH(SqlServer2012以降の場合)を介してページングします。データベース。必要に応じてカプセル化できます。
Whereクエリのさらなるカプセル化については、興味のある人はDapperlamadaクエリを使用して拡張することもできます。
作業単位とトランザクションの定義
コードを表示
データウェアハウスを定義する
コードを表示
通常、T4テンプレートを使用して生成された、独自のニーズに応じて調整または拡張します
データベースリンケージ
Ioptionsモードを介して構成ファイルappsettingsの接続文字列を読み取ります
public class MyDBContext : DapperDBContext
{
public MyDBContext(IOptions<DapperDBContextOptions> optionsAccessor) : base(optionsAccessor)
{
}
protected override IDbConnection CreateConnection(string connectionString)
{
IDbConnection conn = new SqlConnection(connectionString);
return conn;
}
}
第四に、Dapperの使用
Startup.csは、データベース接続文字列を挿入して読み取ります
{
"SQLConnString": "Data Source=(local);Initial Catalog=database;Persist Security Info=True;User ID=sa;Password=123456;MultipleActiveResultSets=True;",
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
services.AddDapperDBContext<MyDBContext>(options =>
{
options.Configuration = Configuration["SQLConnString"];
});
単純な例のWebAPIまたはNetCoreMVCでの呼び出し例:
コードを表示
コードを表示