Einfügen und Aktualisieren mit Dapper durchführen


194

Ich bin an der Verwendung von Dapper interessiert - aber soweit ich das beurteilen kann, werden nur Query and Execute unterstützt. Ich sehe nicht, dass Dapper eine Möglichkeit zum Einfügen und Aktualisieren von Objekten enthält.

Was ist angesichts der Tatsache, dass unser Projekt (die meisten Projekte?) Einfügungen und Aktualisierungen durchführen muss, die beste Vorgehensweise, um neben Dapper Einfügungen und Aktualisierungen durchzuführen?

Vorzugsweise müssten wir nicht auf die ADO.NET-Methode zur Parametererstellung usw. zurückgreifen.

Die beste Antwort, die ich an dieser Stelle finden kann, ist die Verwendung von LinqToSQL für Einfügungen und Aktualisierungen. Gibt es eine bessere Antwort?


3
Es gibt diese Contrib-Erweiterung von Dapper.NET selbst, die ich verwende. github.com/StackExchange/dapper-dot-net/tree/master/…
Rajiv

Antworten:


201

Wir versuchen, ein paar Helfer aufzubauen, entscheiden uns immer noch für APIs und ob dies im Kern liegt oder nicht. Weitere Informationen finden Sie unter: https://code.google.com/archive/p/dapper-dot-net/issues/6 .

In der Zwischenzeit können Sie Folgendes tun

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

und so weiter

Siehe auch meinen Blog-Beitrag: Das nervige INSERT-Problem

Aktualisieren

Wie in den Kommentaren erwähnt, sind im Dapper.Contrib- Projekt jetzt mehrere Erweiterungen in Form dieser IDbConnectionErweiterungsmethoden verfügbar :

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
Hallo Sam, habe deine SO-Antwort bei Google gefunden und ich habe mich gefragt, ob die letzte Codezeile das Wort setals enthalten soll cnn.Execute("update Table SET val = @val where Id = @id", new {val, id = 1});oder ob dies adrett spezifisch ist. Ich bin neu bei dapper und habe nach einem Update-Beispiel gesucht :)
JP Hellemons

1
@ JPHellemons Ich habe es versucht var updateCat = connection.Execute("UPDATE tCategories SET sCategory = @val WHERE iCategoryID = @id", new { val = "dapper test", id = 23 });und es hat funktioniert. Ohne die Verwendung von SET erhalte ich einen SQLException-Syntaxfehler in der Nähe von sCategory.
Teuer


3
@RosdiKasim Besiegt dies nicht den Zweck der Verwendung von Dapper? Ich möchte SQL verwenden. Dies abstrahiert es. Was vermisse ich?
Johnny

2
@johnny Es ist nur eine Hilfsklasse ... einige Leute wollen ihren Code so prägnant wie möglich ... Sie müssen ihn nicht verwenden, wenn Sie ihn nicht wollen.
Rosdi Kasim

67

Das Ausführen von CRUD-Operationen mit Dapper ist eine einfache Aufgabe. Ich habe die folgenden Beispiele erwähnt, die Ihnen bei CRUD-Operationen helfen sollen.

Code für C RUD:

Methode 1: Diese Methode wird verwendet, wenn Sie Werte aus verschiedenen Entitäten einfügen.

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

Methode 2: Diese Methode wird verwendet, wenn Ihre Entitätseigenschaften dieselben Namen wie die SQL-Spalten haben. Dapper als ORM ordnet Entitätseigenschaften den übereinstimmenden SQL-Spalten zu.

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

Code für 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
    });
}

Code für 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
    });
}

Code für 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

Sie können es so machen:

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
Sie sollten verwenden, using-statementdamit die Verbindung auch im Ausnahmefall geschlossen wird.
Tim Schmelter

12
Sie könnten einfach customerEntity direkt übergeben, anstatt einen anonymen Typ zu verwenden ...
Thomas Levesque

@ThomasLevesque Was meinst du damit? Können Sie ein kleines Codebeispiel dafür liefern, was Sie meinen?
iaacp

4
@iaacp, ich meine das:sqlConnection.Execute(sqlQuery, customerEntity);
Thomas Levesque

1
@ThomasLevesque können wir auch mit dem gleichen Muster aktualisieren? dhsqlConnection.Execute(sqlQuery, customerEntity);
Shankar

16

Mit Dapper.Contrib ist es so einfach:

Liste einfügen:

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

Single einfügen:

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

Aktualisierungsliste:

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

Update Single:

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

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


1
Wenn Sie oben ein einzelnes Objekt einfügen, können Sie die neue Identitätsnummer wieder herausholen und wieder in Ihr Modell einfügen ... Aber wie machen Sie das Einfügen einer Liste von Objekten - die Objekte in der Liste haben keine Identitätsfeld. Müssen Sie die Liste durchlaufen und dann einzeln einfügen, um jedes Mal die neue ID zu erhalten?
Harag

1
@harag Wenn du die neue ID woanders brauchst, musst du das wohl so machen. Entity Framework behandelt Referenztypen wie Klassen problemlos mit Einfügungen, aber ich weiß nicht, wie Dapper.Contrib damit funktioniert, wenn dies Ihr Blickwinkel war.
Ogglas

5
@ Ogglas, danke. Ich habe festgestellt, dass "connection.Insert (myObject)" die Eigenschaft "[key]" des "myObject" aktualisiert, wenn ich nur ein Objekt einfüge, aber wenn ich eine Liste von beispielsweise 5 Objekten mit demselben einfüge "connection.Insert (myObjectList)", dann wird keine der [Schlüssel] -Eigenschaften aktualisiert, sodass ich jedes Element in der Liste manuell ausführen und einzeln einfügen muss.
Harag

1
In conn.Update(yourClass)wenn einige Eigenschaften sind null , dann Aktualisieren Sie die Felder auf NULL ? Funktioniert nicht. Aktualisieren Sie das Feld auf NULL . Not partials updates
Kiquenet

5

Sie können dapper auch mit einer gespeicherten Prozedur und einer generischen Methode verwenden, mit der alles leicht verwaltet werden kann.

Definieren Sie Ihre Verbindung:

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

Erstellen Sie eine Schnittstelle, um die Dapper-Methoden zu definieren, die Sie tatsächlich benötigen:

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

Implementieren Sie die Schnittstelle:

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

    }

Sie können jetzt nach Bedarf vom Modell aus anrufen:

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

Sie können auch Parameter übergeben:

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

        }

Rufen Sie jetzt von Ihren Controllern aus:

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

Ich hoffe, es verhindert die Wiederholung Ihres Codes und bietet Sicherheit.


1

Sie können dies versuchen:

 string sql = "UPDATE Customer SET City = @City WHERE CustomerId = @CustomerId";             
 conn.Execute(sql, customerEntity);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.