231

Dapperの使用に興味がありますが、私が知る限り、Dapperはクエリと実行のみをサポートしています。Dapperにオブジェクトの挿入と更新の方法が含まれているのがわかりません。

私たちのプロジェクト(ほとんどのプロジェクト?)が挿入と更新を行う必要があるとすると、dapperと一緒に挿入と更新を行うためのベストプラクティスは何ですか?

できれば、パラメータ構築などのADO.NETメソッドに頼る必要はありません。

この時点で私が思いつくことができる最善の答えは、挿入と更新にLinqToSQLを使用することです。より良い答えはありますか?

4

9 に答える 9

240

私たちはいくつかのヘルパーを構築することを検討していますが、それでもAPIを決定し、これがコアになるかどうかを決定します。進捗状況については、 https://code.google.com/archive/p/dapper-dot-net/issues/6を参照してください。

それまでの間、次のことができます

val = "my value";
cnn.Execute("insert into Table(val) values (@val)", new {val});

cnn.Execute("update Table set val = @val where Id = @id", new {val, id = 1});

etcetera

私のブログ投稿も参照してください:その厄介なINSERTの問題

アップデート

コメントで指摘されているように、Dapper.Contribプロジェクトでは、次のIDbConnection拡張メソッドの形式でいくつかの拡張機能を利用できます。

T Get<T>(id);
IEnumerable<T> GetAll<T>();
int Insert<T>(T obj);
int Insert<T>(Enumerable<T> list);
bool Update<T>(T obj);
bool Update<T>(Enumerable<T> list);
bool Delete<T>(T obj);
bool Delete<T>(Enumerable<T> list);
bool DeleteAll<T>();
于 2011-05-11T12:45:30.387 に答える
86

Dapperを使用してCRUD操作を実行するのは簡単な作業です。CRUD操作で役立つはずの以下の例について説明しました。

C RUDのコード:

方法1:この方法は、さまざまなエンティティから値を挿入するときに使用されます。

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDbConnection"].ConnectionString))
{
    string insertQuery = @"INSERT INTO [dbo].[Customer]([FirstName], [LastName], [State], [City], [IsActive], [CreatedOn]) VALUES (@FirstName, @LastName, @State, @City, @IsActive, @CreatedOn)";

    var result = db.Execute(insertQuery, new
    {
        customerModel.FirstName,
        customerModel.LastName,
        StateModel.State,
        CityModel.City,
        isActive,
        CreatedOn = DateTime.Now
    });
}

方法2:この方法は、エンティティプロパティの名前がSQL列と同じ場合に使用されます。したがって、ORMであるDapperは、エンティティプロパティを一致するSQL列にマップします。

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDbConnection"].ConnectionString))
{
    string insertQuery = @"INSERT INTO [dbo].[Customer]([FirstName], [LastName], [State], [City], [IsActive], [CreatedOn]) VALUES (@FirstName, @LastName, @State, @City, @IsActive, @CreatedOn)";

    var result = db.Execute(insertQuery, customerViewModel);
}

C R UDのコード:

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDbConnection"].ConnectionString))
{
    string selectQuery = @"SELECT * FROM [dbo].[Customer] WHERE FirstName = @FirstName";

    var result = db.Query(selectQuery, new
    {
        customerModel.FirstName
    });
}

CR U Dのコード:

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDbConnection"].ConnectionString))
{
    string updateQuery = @"UPDATE [dbo].[Customer] SET IsActive = @IsActive WHERE FirstName = @FirstName AND LastName = @LastName";

    var result = db.Execute(updateQuery, new
    {
        isActive,
        customerModel.FirstName,
        customerModel.LastName
    });
}

CRU Dのコード:

using (IDbConnection db = new SqlConnection(ConfigurationManager.ConnectionStrings["myDbConnection"].ConnectionString))
{
    string deleteQuery = @"DELETE FROM [dbo].[Customer] WHERE FirstName = @FirstName AND LastName = @LastName";

    var result = db.Execute(deleteQuery, new
    {
        customerModel.FirstName,
        customerModel.LastName
    });
}
于 2016-07-03T08:09:32.420 に答える
27

あなたはそのような方法でそれを行うことができます:

sqlConnection.Open();

string sqlQuery = "INSERT INTO [dbo].[Customer]([FirstName],[LastName],[Address],[City]) VALUES (@FirstName,@LastName,@Address,@City)";
sqlConnection.Execute(sqlQuery,
    new
    {
        customerEntity.FirstName,
        customerEntity.LastName,
        customerEntity.Address,
        customerEntity.City
    });

sqlConnection.Close();
于 2011-07-05T07:17:57.313 に答える
23

Dapper.Contribを使用すると、次のように簡単になります。

リストを挿入:

public int Insert(IEnumerable<YourClass> yourClass)
{
    using (SqlConnection conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        return conn.Insert(yourClass) ;
    }
}

シングルを挿入:

public int Insert(YourClass yourClass)
{
    using (SqlConnection conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        return conn.Insert(yourClass) ;
    }
}

更新リスト:

public bool Update(IEnumerable<YourClass> yourClass)
{
    using (SqlConnection conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        return conn.Update(yourClass) ;
    }
}

シングルアップデート:

public bool Update(YourClass yourClass)
{
    using (SqlConnection conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        return conn.Update(yourClass) ;
    }
}

ソース:https ://github.com/StackExchange/Dapper/tree/master/Dapper.Contrib

于 2017-04-24T20:02:04.053 に答える
7

また、すべてを簡単に管理できるストアドプロシージャと一般的な方法でdapperを使用することもできます。

接続を定義します。

public class Connection: IDisposable
{
    private static SqlConnectionStringBuilder ConnectionString(string dbName)
    {
        return new SqlConnectionStringBuilder
            {
                ApplicationName = "Apllication Name",
                DataSource = @"Your source",
                IntegratedSecurity = false,
                InitialCatalog = Database Name,
                Password = "Your Password",
                PersistSecurityInfo = false,
                UserID = "User Id",
                Pooling = true
            };
    }

    protected static IDbConnection LiveConnection(string dbName)
    {
        var connection = OpenConnection(ConnectionString(dbName));
        connection.Open();
        return connection;
    }

    private static IDbConnection OpenConnection(DbConnectionStringBuilder connectionString)
    {
        return new SqlConnection(connectionString.ConnectionString);
    }

    protected static bool CloseConnection(IDbConnection connection)
    {
        if (connection.State != ConnectionState.Closed)
        {
            connection.Close();
            // connection.Dispose();
        }
        return true;
    }

    private static void ClearPool()
    {
        SqlConnection.ClearAllPools();
    }

    public void Dispose()
    {
        ClearPool();
    }
}

実際に必要なDapperメソッドを定義するためのインターフェースを作成します。

 public interface IDatabaseHub
    {
   long Execute<TModel>(string storedProcedureName, TModel model, string dbName);

        /// <summary>
        /// This method is used to execute the stored procedures with parameter.This is the generic version of the method.
        /// </summary>
        /// <param name="storedProcedureName">This is the type of POCO class that will be returned. For more info, refer to https://msdn.microsoft.com/en-us/library/vstudio/dd456872(v=vs.100).aspx. </param>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="model">The model object containing all the values that passes as Stored Procedure's parameter.</param>
        /// <returns>Returns how many rows have been affected.</returns>
        Task<long> ExecuteAsync<TModel>(string storedProcedureName, TModel model, string dbName);

        /// <summary>
        /// This method is used to execute the stored procedures with parameter. This is the generic version of the method.
        /// </summary>
        /// <param name="storedProcedureName">Stored Procedure's name. Expected to be a Verbatim String, e.g. @"[Schema].[Stored-Procedure-Name]"</param>
        /// <param name="parameters">Parameter required for executing Stored Procedure.</param>        
        /// <returns>Returns how many rows have been affected.</returns>         
        long Execute(string storedProcedureName, DynamicParameters parameters, string dbName);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="storedProcedureName"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        Task<long> ExecuteAsync(string storedProcedureName, DynamicParameters parameters, string dbName);
}

インターフェイスを実装します。

     public class DatabaseHub : Connection, IDatabaseHub
        {

 /// <summary>
        /// This function is used for validating if the Stored Procedure's name is correct.
        /// </summary>
        /// <param name="storedProcedureName">Stored Procedure's name. Expected to be a Verbatim String, e.g. @"[Schema].[Stored-Procedure-Name]"</param>
        /// <returns>Returns true if name is not empty and matches naming patter, otherwise returns false.</returns>

        private static bool IsStoredProcedureNameCorrect(string storedProcedureName)
        {
            if (string.IsNullOrEmpty(storedProcedureName))
            {
                return false;
            }

            if (storedProcedureName.StartsWith("[") && storedProcedureName.EndsWith("]"))
            {
                return Regex.IsMatch(storedProcedureName,
                    @"^[\[]{1}[A-Za-z0-9_]+[\]]{1}[\.]{1}[\[]{1}[A-Za-z0-9_]+[\]]{1}$");
            }
            return Regex.IsMatch(storedProcedureName, @"^[A-Za-z0-9]+[\.]{1}[A-Za-z0-9]+$");
        }

     /// <summary>
            /// This method is used to execute the stored procedures without parameter.
            /// </summary>
            /// <param name="storedProcedureName">Stored Procedure's name. Expected to be a Verbatim String, e.g. @"[Schema].[Stored-Procedure-Name]"</param>
            /// <param name="model">The model object containing all the values that passes as Stored Procedure's parameter.</param>
            /// <typeparam name="TModel">This is the type of POCO class that will be returned. For more info, refer to https://msdn.microsoft.com/en-us/library/vstudio/dd456872(v=vs.100).aspx. </typeparam>
            /// <returns>Returns how many rows have been affected.</returns>

            public long Execute<TModel>(string storedProcedureName, TModel model, string dbName)
            {
                if (!IsStoredProcedureNameCorrect(storedProcedureName))
                {
                    return 0;
                }

                using (var connection = LiveConnection(dbName))
                {
                    try
                    {
                        return connection.Execute(
                            sql: storedProcedureName,
                            param: model,
                            commandTimeout: null,
                            commandType: CommandType.StoredProcedure
                            );

                    }
                    catch (Exception exception)
                    {
                        throw exception;
                    }
                    finally
                    {
                        CloseConnection(connection);
                    }
                }
            }

            public async Task<long> ExecuteAsync<TModel>(string storedProcedureName, TModel model, string dbName)
            {
                if (!IsStoredProcedureNameCorrect(storedProcedureName))
                {
                    return 0;
                }

                using (var connection = LiveConnection(dbName))
                {
                    try
                    {
                        return await connection.ExecuteAsync(
                            sql: storedProcedureName,
                            param: model,
                            commandTimeout: null,
                            commandType: CommandType.StoredProcedure
                            );

                    }
                    catch (Exception exception)
                    {
                        throw exception;
                    }
                    finally
                    {
                        CloseConnection(connection);
                    }
                }
            }

            /// <summary>
            /// This method is used to execute the stored procedures with parameter. This is the generic version of the method.
            /// </summary>
            /// <param name="storedProcedureName">Stored Procedure's name. Expected to be a Verbatim String, e.g. @"[Schema].[Stored-Procedure-Name]"</param>
            /// <param name="parameters">Parameter required for executing Stored Procedure.</param>        
            /// <returns>Returns how many rows have been affected.</returns>

            public long Execute(string storedProcedureName, DynamicParameters parameters, string dbName)
            {
                if (!IsStoredProcedureNameCorrect(storedProcedureName))
                {
                    return 0;
                }

                using (var connection = LiveConnection(dbName))
                {
                    try
                    {
                        return connection.Execute(
                            sql: storedProcedureName,
                            param: parameters,
                            commandTimeout: null,
                            commandType: CommandType.StoredProcedure
                            );
                    }
                    catch (Exception exception)
                    {
                        throw exception;
                    }
                    finally
                    {
                        CloseConnection(connection);
                    }
                }
            }



            public async Task<long> ExecuteAsync(string storedProcedureName, DynamicParameters parameters, string dbName)
            {
                if (!IsStoredProcedureNameCorrect(storedProcedureName))
                {
                    return 0;
                }

                using (var connection = LiveConnection(dbName))
                {
                    try
                    {
                        return await connection.ExecuteAsync(
                            sql: storedProcedureName,
                            param: parameters,
                            commandTimeout: null,
                            commandType: CommandType.StoredProcedure
                            );

                    }
                    catch (Exception exception)
                    {
                        throw exception;
                    }
                    finally
                    {
                        CloseConnection(connection);
                    }
                }
            }

    }

これで、必要に応じてモデルから呼び出すことができます。

public class DeviceDriverModel : Base
    {
 public class DeviceDriverSaveUpdate
        {
            public string DeviceVehicleId { get; set; }
            public string DeviceId { get; set; }
            public string DriverId { get; set; }
            public string PhoneNo { get; set; }
            public bool IsActive { get; set; }
            public string UserId { get; set; }
            public string HostIP { get; set; }
        }


        public Task<long> DeviceDriver_SaveUpdate(DeviceDriverSaveUpdate obj)
        {

            return DatabaseHub.ExecuteAsync(
                    storedProcedureName: "[dbo].[sp_SaveUpdate_DeviceDriver]", model: obj, dbName: AMSDB);//Database name defined in Base Class.
        }
}

パラメータを渡すこともできます。

public Task<long> DeleteFuelPriceEntryByID(string FuelPriceId, string UserId)
        {


            var parameters = new DynamicParameters();
            parameters.Add(name: "@FuelPriceId", value: FuelPriceId, dbType: DbType.Int32, direction: ParameterDirection.Input);
            parameters.Add(name: "@UserId", value: UserId, dbType: DbType.String, direction: ParameterDirection.Input);

            return DatabaseHub.ExecuteAsync(
                    storedProcedureName: @"[dbo].[sp_Delete_FuelPriceEntryByID]", parameters: parameters, dbName: AMSDB);

        }

次に、コントローラーから呼び出します。

var queryData = new DeviceDriverModel().DeviceInfo_Save(obj);

コードの繰り返しを防ぎ、セキュリティを提供することを願っています。

于 2019-01-13T11:22:23.550 に答える
3

クエリ操作にサードパーティのライブラリを使用する代わりに、自分でクエリを作成することをお勧めします。他のサードパーティパッケージを使用すると、dapperを使用する主な利点、つまりクエリを作成する柔軟性が失われるためです。

現在、オブジェクト全体の挿入または更新クエリの記述に問題があります。このために、以下のようなヘルパーを簡単に作成できます。

InsertQueryBuilder:

 public static string InsertQueryBuilder(IEnumerable < string > fields) {


  StringBuilder columns = new StringBuilder();
  StringBuilder values = new StringBuilder();


  foreach(string columnName in fields) {
   columns.Append($ "{columnName}, ");
   values.Append($ "@{columnName}, ");

  }
  string insertQuery = $ "({ columns.ToString().TrimEnd(',', ' ')}) VALUES ({ values.ToString().TrimEnd(',', ' ')}) ";

  return insertQuery;
 }

これで、挿入する列の名前を渡すだけで、次のようにクエリ全体が自動的に作成されます。

List < string > columns = new List < string > {
 "UserName",
 "City"
}
//QueryBuilder is the class having the InsertQueryBuilder()
string insertQueryValues = QueryBuilderUtil.InsertQueryBuilder(columns);

string insertQuery = $ "INSERT INTO UserDetails {insertQueryValues} RETURNING UserId";

Guid insertedId = await _connection.ExecuteScalarAsync < Guid > (insertQuery, userObj);

TableNameパラメーターを渡すことにより、INSERTステートメント全体を返すように関数を変更することもできます。

Classプロパティ名がデータベースのフィールド名と一致していることを確認してください。次に、obj全体(この場合はuserObjなど)を渡すことができるのはあなただけであり、値は自動的にマップされます。

同様に、UPDATEクエリのヘルパー関数も使用できます。

  public static string UpdateQueryBuilder(List < string > fields) {
   StringBuilder updateQueryBuilder = new StringBuilder();

   foreach(string columnName in fields) {
    updateQueryBuilder.AppendFormat("{0}=@{0}, ", columnName);
   }
   return updateQueryBuilder.ToString().TrimEnd(',', ' ');
  }

そしてそれを次のように使用します:

List < string > columns = new List < string > {
 "UserName",
 "City"
}
//QueryBuilder is the class having the UpdateQueryBuilder()
string updateQueryValues = QueryBuilderUtil.UpdateQueryBuilder(columns);

string updateQuery =  $"UPDATE UserDetails SET {updateQueryValues} WHERE UserId=@UserId";

await _connection.ExecuteAsync(updateQuery, userObj);

これらのヘルパー関数でも、挿入または更新するフィールドの名前を渡す必要がありますが、少なくともクエリを完全に制御でき、必要に応じてさまざまなWHERE句を含めることもできます。

このヘルパー関数を使用して、次のコード行を保存します。

クエリの挿入の場合:

 $ "INSERT INTO UserDetails (UserName,City) VALUES (@UserName,@City) RETURNING UserId";

更新クエリの場合:

$"UPDATE UserDetails SET UserName=@UserName, City=@City WHERE UserId=@UserId";

数行のコードの違いがあるようですが、10フィールドを超えるテーブルで挿入または更新操作を実行する場合、違いを感じることができます。

nameof演算子を使用して、タイプミスを回避するために関数内のフィールド名を渡すことができます

それ以外の:

List < string > columns = new List < string > {
 "UserName",
 "City"
}

あなたは書ける:

List < string > columns = new List < string > {
nameof(UserEntity.UserName),
nameof(UserEntity.City),
}
于 2020-07-06T05:48:35.983 に答える
1

あなたはこれを試すことができます:

 string sql = "UPDATE Customer SET City = @City WHERE CustomerId = @CustomerId";             
 conn.Execute(sql, customerEntity);
于 2018-09-25T16:57:55.813 に答える
0

これは簡単な例Repository Patternです:

public interface IUserRepository
{
    Task<bool> CreateUser(User user);
    Task<bool> UpdateUser(User user);
}

そしてでUserRepository

public class UserRepository: IUserRepository
    {
        private readonly IConfiguration _configuration;

        public UserRepository(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public async Task<bool> CreateUser(User user)
        {
            using var connection = new NpgsqlConnection(_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

            var affected =
                await connection.ExecuteAsync
                    ("INSERT INTO User (Name, Email, Mobile) VALUES (@Name, @Email, @Mobile)",
                            new { Name= user.Name, Email= user.Email, Mobile = user.Mobile});

            if (affected == 0)
                return false;

            return true;
        }

        public async Task<bool> UpdateUser(User user)
        {
            using var connection = new NpgsqlConnection(_configuration.GetValue<string>("DatabaseSettings:ConnectionString"));

            var affected = await connection.ExecuteAsync
                    ("UPDATE User SET Name=@Name, Email= @Email, Mobile = @Mobile WHERE Id = @Id",
                            new { Name= user.Name, Email= user.Email, Mobile  = user.Mobile , Id = user.Id });

            if (affected == 0)
                return false;

            return true;
        }
    }

注:PostgreSQLデータベースのNpgsqlConnection取得に使用されますConnectionString

于 2021-10-05T15:58:50.903 に答える
0

ストアドプロシージャ+DapperメソッドまたはSQL挿入ステートメント+Dapperが機能しますが、SQLテーブル列を使用した動的マッピングデータモデルであるORMの概念を完全には満たしていません。これは、上記の2つのアプローチのいずれかを使用する場合でも、ハードコードが必要になるためです。ストアドプロシージャパラメータまたはSQL挿入ステートメントの列名の値。

コード変更を最小限に抑えるという懸念を解決するために、Dapper.Contribを使用してSQL挿入をサポートできます。これが公式ガイドであり、以下にサンプルのセットアップとコードがあります。

ステップ1

C#でクラスモデルを設定しますDapper.Contrib.Extensions。: [Table]属性はSQLボックス内の目的のテーブル名を指し、[ExplicitKey]属性はDapperにこのモデルプロパティがSQLテーブルの主キーであることを通知します。

[Table("MySQLTableName")]
public class UserModel
{
    [ExplicitKey]
    public string UserId { get; set; }
    public string Name { get; set; }
    public string Sex { get; set; }
}

ステップ2

SQLデータベース/テーブルを次のように設定します。

ここに画像の説明を入力してください

ステップ3

次に、C#コードを次のようにビルドします。次の名前空間を使用する必要があります。

using Dapper.Contrib.Extensions;
using System.Data;

コード:

string connectionString = "Server=localhost;Database=SampleSQL_DB;Integrated Security=True";

UserModel objUser1 = new UserModel { UserId = "user0000001" , Name = "Jack", Sex = "Male" };
UserModel objUser2 = new UserModel { UserId = "user0000002", Name = "Marry", Sex = "female" };
UserModel objUser3 = new UserModel { UserId = "user0000003", Name = "Joe", Sex = "male" };

List<UserModel> LstUsers = new List<UserModel>();
LstUsers.Add(objUser2); LstUsers.Add(objUser3);

try
{
    using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(connectionString))
    {
        connection.Open();

        using (var trans = connection.BeginTransaction())
        {
            try
            {
                //  insert single record with custom data model
                connection.Insert(objUser1, transaction: trans);

                // insert multiple record with List<Type>
                connection.Insert(LstUsers, transaction: trans);

                // Only save to SQL database if all require SQL operation completed successfully 
                trans.Commit();
            }
            catch (Exception e)
            {
                // If one of the SQL operation fail , roll back the whole transaction
                trans.Rollback();
            }
        }
    }
}
catch (Exception e) { }
于 2021-11-17T08:33:08.123 に答える