我对使用Dapper很感兴趣,但据我所知,它只支持查询和执行。我没有看到Dapper包含插入和更新对象的方法。
假设我们的项目(大多数项目?)需要进行插入和更新,那么与dapper一起进行插入和更新的最佳实践是什么?
我们最好不要诉诸于ADO。NET参数构建方法等。
在这一点上,我能想到的最佳答案是使用LinqToSQL进行插入和更新。还有更好的答案吗?
我对使用Dapper很感兴趣,但据我所知,它只支持查询和执行。我没有看到Dapper包含插入和更新对象的方法。
假设我们的项目(大多数项目?)需要进行插入和更新,那么与dapper一起进行插入和更新的最佳实践是什么?
我们最好不要诉诸于ADO。NET参数构建方法等。
在这一点上,我能想到的最佳答案是使用LinqToSQL进行插入和更新。还有更好的答案吗?
当前回答
与其使用任何第三方库进行查询操作,我宁愿建议您自己编写查询。因为使用任何其他第三方包会带走使用dapper的主要优势,即编写查询的灵活性。
现在,为整个对象编写Insert或Update查询有一个问题。为此,你可以简单地创建如下所示的helper:
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查询的helper函数:
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子句。
通过这些helper函数,你将保存以下代码行:
插入查询:
$ "INSERT INTO UserDetails (UserName,City) VALUES (@UserName,@City) RETURNING UserId";
更新查询:
$"UPDATE UserDetails SET UserName=@UserName, City=@City WHERE UserId=@UserId";
这似乎是几行代码的区别,但是当涉及到对具有超过10个字段的表执行插入或更新操作时,就可以感受到区别。
您可以使用操作符的名称来传递函数中的字段名称,以避免键入错误
而不是:
List < string > columns = new List < string > {
"UserName",
"City"
}
你可以这样写:
List < string > columns = new List < string > {
nameof(UserEntity.UserName),
nameof(UserEntity.City),
}
其他回答
使用Dapper执行CRUD操作是一项简单的任务。我已经提到了下面的示例,它们应该可以帮助您进行CRUD操作。
CRUD代码:
方法#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列具有相同的名称时使用此方法。因此,Dapper作为ORM将实体属性与匹配的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);
}
CRUD代码:
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
});
}
CRUD代码:
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
});
}
CRUD代码:
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
});
}
下面是一个关于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;
}
}
注意:NpgsqlConnection用于获取PostgreSQL数据库的ConnectionString
使用短小精悍的。它是如此简单:
插入列表:
public int Insert(IEnumerable<YourClass> yourClass)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
return conn.Insert(yourClass) ;
}
}
插入单:
public int Insert(YourClass yourClass)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
return conn.Insert(yourClass) ;
}
}
更新列表:
public bool Update(IEnumerable<YourClass> yourClass)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
return conn.Update(yourClass) ;
}
}
更新单:
public bool Update(YourClass yourClass)
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
return conn.Update(yourClass) ;
}
}
来源:https://github.com/StackExchange/Dapper/tree/master/Dapper.Contrib
与其使用任何第三方库进行查询操作,我宁愿建议您自己编写查询。因为使用任何其他第三方包会带走使用dapper的主要优势,即编写查询的灵活性。
现在,为整个对象编写Insert或Update查询有一个问题。为此,你可以简单地创建如下所示的helper:
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查询的helper函数:
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子句。
通过这些helper函数,你将保存以下代码行:
插入查询:
$ "INSERT INTO UserDetails (UserName,City) VALUES (@UserName,@City) RETURNING UserId";
更新查询:
$"UPDATE UserDetails SET UserName=@UserName, City=@City WHERE UserId=@UserId";
这似乎是几行代码的区别,但是当涉及到对具有超过10个字段的表执行插入或更新操作时,就可以感受到区别。
您可以使用操作符的名称来传递函数中的字段名称,以避免键入错误
而不是:
List < string > columns = new List < string > {
"UserName",
"City"
}
你可以这样写:
List < string > columns = new List < string > {
nameof(UserEntity.UserName),
nameof(UserEntity.City),
}
你可以试试这个:
string sql = "UPDATE Customer SET City = @City WHERE CustomerId = @CustomerId";
conn.Execute(sql, customerEntity);