Melakukan Sisipan dan Pembaruan dengan Dapper


194

Saya tertarik menggunakan Dapper - tetapi dari apa yang saya tahu itu hanya mendukung Query dan Execute. Saya tidak melihat bahwa Dapper termasuk cara Memasukkan dan Memperbarui objek.

Mengingat bahwa proyek kami (sebagian besar proyek?) Perlu melakukan sisipan dan pembaruan, apa praktik terbaik untuk melakukan Sisipan dan Pembaruan bersama necis?

Lebih disukai kita tidak perlu menggunakan metode ADO.NET untuk membangun parameter, dll.

Jawaban terbaik yang dapat saya temukan pada saat ini adalah menggunakan LinqToSQL untuk memasukkan dan memperbarui. Apakah ada jawaban yang lebih baik?


3
Ada ekstensi Contrib ini dari Dapper.NET sendiri yang saya gunakan. github.com/StackExchange/dapper-dot-net/tree/master/…
Rajiv

Jawaban:


201

Kami sedang membangun beberapa pembantu, masih memutuskan API dan apakah ini berjalan pada intinya atau tidak. Lihat: https://code.google.com/archive/p/dapper-dot-net/issues/6 untuk kemajuan.

Sementara itu, Anda dapat melakukan hal berikut

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

dan sebagainya

Lihat juga posting blog saya: Masalah INSERT yang menjengkelkan itu

Memperbarui

Seperti yang ditunjukkan dalam komentar, sekarang ada beberapa ekstensi yang tersedia di proyek Dapper.Contrib dalam bentuk IDbConnectionmetode ekstensi ini :

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

4
Hai Sam, temukan jawaban SO Anda dengan google dan saya bertanya-tanya apakah baris kode terakhir harus memasukkan kata setas cnn.Execute("update Table SET val = @val where Id = @id", new {val, id = 1});atau apakah ini necis spesifik? Saya baru mengenal necis dan sedang mencari contoh pembaruan :)
JP Hellemons

1
@ JPHellemons Saya mencoba ini var updateCat = connection.Execute("UPDATE tCategories SET sCategory = @val WHERE iCategoryID = @id", new { val = "dapper test", id = 23 });dan itu berhasil. Tanpa menggunakan SET saya mendapatkan kesalahan sintaks SQLException dekat sCategory.
Pricey


3
@RosdiKasim Bukankah ini mengalahkan tujuan menggunakan Dapper? Saya ingin menggunakan SQL. Ini abstraknya. Apa yang saya lewatkan?
johnny

2
@ Johnny Ini hanya kelas pembantu ... beberapa orang ingin kode mereka sesingkat mungkin ... Anda tidak harus menggunakannya jika Anda tidak menginginkannya.
Rosdi Kasim

67

Melakukan operasi CRUD menggunakan Dapper adalah tugas yang mudah. Saya telah menyebutkan contoh di bawah ini yang dapat membantu Anda dalam operasi CRUD.

Kode untuk C RUD:

Metode # 1: Metode ini digunakan ketika Anda memasukkan nilai dari entitas yang berbeda.

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

Metode # 2: Metode ini digunakan ketika properti entitas Anda memiliki nama yang sama dengan kolom SQL. Jadi, Dapper menjadi properti entitas peta ORM dengan kolom SQL yang cocok.

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

Kode untuk 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
    });
}

Kode untuk 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
    });
}

Kode untuk 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
    });
}

26

Anda bisa melakukannya dengan cara seperti ini:

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

36
Anda harus menggunakan using-statementsehingga koneksi menjadi tertutup bahkan dalam kasus pengecualian.
Tim Schmelter

12
Anda bisa melewati customerEntity langsung daripada menggunakan jenis anonim ...
Thomas Levesque

@ThomasLevesque Apa yang Anda maksud dengan itu? Bisakah Anda memberikan contoh kode kecil tentang apa yang Anda maksud?
iaacp

4
@iaacp, maksud saya:sqlConnection.Execute(sqlQuery, customerEntity);
Thomas Levesque

1
@ThomasLevesque dapatkah kita melakukan pembaruan juga menggunakan pola yang sama? yaitu,sqlConnection.Execute(sqlQuery, customerEntity);
Shankar

16

Menggunakan Dapper.Contrib semudah ini:

Sisipkan daftar:

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

Sisipkan tunggal:

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

Perbarui daftar:

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

Perbarui tunggal:

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

Sumber: https://github.com/StackExchange/Dapper/tree/master/Dapper.Contrib


1
Dengan menggunakan di atas untuk menyisipkan satu objek, Anda bisa mendapatkan nomor identitas baru kembali dan memasukkannya kembali ke dalam model Anda ... Tapi bagaimana Anda melakukannya untuk memasukkan daftar objek - objek dalam daftar tidak memiliki bidang identitas. Apakah Anda harus mengulangi daftar dan kemudian memasukkannya satu per satu, mengeluarkan ID baru setiap kali?
Harag

1
@harag Jika Anda memerlukan ID baru di tempat lain, saya kira Anda harus melakukannya seperti itu. Entity Framework menangani tipe referensi, seperti kelas, tanpa masalah dengan sisipan tapi saya tidak tahu bagaimana Dapper.Contrib bekerja dengan itu jika itu adalah sudut pandang Anda.
Ogglas

5
@ Ogglas, terima kasih. Saya perhatikan "connection.Insert (myObject)" akan memperbarui properti "[key]" dari "myObject" jika saya hanya memasukkan satu objek, tetapi jika saya menyisipkan daftar katakanlah 5 objek menggunakan hal yang sama "connection.Insert (myObjectList)" maka tidak ada properti [kunci] yang diperbarui, jadi saya harus secara manual melakukan foreach item dalam daftar dan memasukkannya satu per satu.
Harag

1
Dalam conn.Update(yourClass)jika beberapa sifat yang nol , maka UPDATE ladang untuk NULL ? Tidak bekerja Perbarui bidang ke NULL . Not partials updates
Kiquenet

5

Anda juga dapat menggunakan necis dengan prosedur tersimpan dan cara umum yang dengannya semuanya mudah dikelola.

Tentukan koneksi Anda:

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

Buat antarmuka untuk menentukan metode Dapper yang sebenarnya Anda butuhkan:

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

Implementasikan antarmuka:

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

    }

Anda sekarang dapat menelepon dari model sesuai kebutuhan Anda:

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

Anda juga dapat mengirimkan parameter:

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

        }

Sekarang telepon dari pengontrol Anda:

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

Semoga itu mencegah pengulangan kode Anda dan memberikan keamanan;


1

Anda dapat mencoba ini:

 string sql = "UPDATE Customer SET City = @City WHERE CustomerId = @CustomerId";             
 conn.Execute(sql, customerEntity);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.