[英]Connection design issue in Dapper, UoW, Generic Repository and multiple databases
[英]connection is null in dapper UOW , when use in loop
我正在使用具有工作单元和存储库模式的 Dapper
我的伍伦贡大学 class
public interface IDapperUnitOfWork
{
IXYZRepository XYZ{ get; }
}
和
public class DapperUnitOfWork : IDisposable, IDapperUnitOfWork
{
private IDbConnection _connection;
private IDbTransaction _transaction;
private IXYZRepository xyzRepository;
public DapperUnitOfWork(string connectionString)
{
_connection = new SqlConnection(connectionString);
_connection.Open();
_transaction = _connection.BeginTransaction();
}
public IXYZRepository XYZ
{
get
{
return xyzRepository ?? (XYZRepository = new XYZRepository (_transaction));
}
}
public void Begin()
{
_transaction = _connection.BeginTransaction();
}
public void Commit()
{
_transaction.Commit();
}
public void Dispose()
{
if (_transaction != null)
_transaction.Dispose();
_transaction = null;
}
public void Rollback()
{
_transaction.Rollback();
}
}
和我的资料库
public interface IXYZRepository
{
public bool SaveSomeData(T data);
}
和
public class IXYZRepository : XYZRepository
{
private IDbTransaction _transaction;
private IDbConnection _connection { get { return _transaction.Connection; } }
public bool SaveSomeData(T data)
{
_connection.Execuet<T>("sp name here" ,
new {//params here}),
_transaction,
commandType: CommandType.StoredProcedure);
}
}
如果我使用它一次,这工作正常,但如果我不得不在循环中使用它而不是在方法 SaveSomeData 中,_connction 是 null 引发 object 参考错误
例子
using (DapperUnitOfWork dapper = new DapperUnitOfWork(_connectionString))
{
foreach (var item in data)
{
dapper.XYZ.SaveSomeData (item);
}
}
在 SaveSomeData 中的第二次循环迭代
_connection.Execuet<T>("sp name here" ,
new {//params here}),
_transaction,
commandType: CommandType.StoredProcedure);
在上面的行 _connection 得到 null 并抛出异常。
谁能建议,如何避免这种情况,这个 UOW 设计有什么错误吗?
更新 1:
迭代后检查 IDbTransaction _transaction 的值
您应该使用“使用”来关闭和处理您的连接,而不是显式关闭它。 当 conn 退出 scope 并被处置时,ado 连接将关闭。
如果您有一个存储过程,那么围绕它的显式事务可能毫无意义。 一个简单的更新存储过程或一个复杂的存储过程将有一个隐式事务,它本身应该封装一个具有回滚条件的事务。 因为,根据定义,一个复杂的存储过程很可能有复杂的标准,这些标准是特定于它正在做的事情的。 您的存储库不需要了解这些条件,事实上,如果存储过程很复杂,实施回滚会更加复杂。
dapper 用法的一个简单示例(顺便说一句,这是一个可用的应用程序):
public async Task<List<AddressVM>> GetAddressesByTypeAsync(int addressTypeId)
{
using var conn = new SqlConnection(connectionString);
var qrystring =
@"SELECT Id
, AddressTypeId
, CompanyName
, Address1
, Address2
, Address3
, Address4
, PostCode
, IsCurrentAgent
FROM Addresses
Where AddressTypeId = @AddressTypeId;";
var qry = await conn.QueryAsync<AddressVM>(qrystring, param: new {AddressTypeId = addressTypeId });
var result = qry.ToList();
return result;
}
因为我使用了 var conn,conn 将在代码退出此任务时关闭并处置。 它将在执行查询时自动打开。 无需明确打开它。
您可以将表类型参数与 dapper 和存储过程一起使用,而不是重复调用。
这将允许您将表传递到存储过程中,然后在一个 go 中插入或更新该批次。这比多次调用更有效。 要清楚,存储过程的参数将是一个表而不是多个变量。
然后可以在一次调用中设置处理。
我在我目前不拥有或无法访问的代码中使用了这种方法,但这篇文章看起来不错:
https://bornsql.ca/blog/table-valued-parameters-and-dapper-in.net-core/
他正在使用它来读取数据,但您显然可以在存储过程中进行更新。
await Query<SearchResultTable>("[dbo].[SearchByLocationIds]", parameters).ConfigureAwait(false);
文章中的其他代码。
table参数需要在sql服务器中定义,这只是一个integer当然也可以像table一样有多个column
CREATE TYPE TVP_Integer AS TABLE
(
[Value] INT NULL
);
GO
我想你可以只传递一个数据表,但他使用了一个 ienumerable。
private static IEnumerable<SqlDataRecord> CreateSqlDataRecord(IEnumerable<int> list)
{
var metaData = new SqlMetaData("Value", SqlDbType.Int);
var record = new SqlDataRecord(_metaData);
foreach (var item in list)
{
record.SetInt32(0, item);
yield return record;
}
}
注意 AsTableValuedParameter 扩展方法
public static SqlMapper.ICustomQueryParameter GetTableValuedParameter(this int[] list)
{
if (!ValidateList(list))
{
list = new int[] { };
}
return CreateSqlDataRecord(list).AsTableValuedParameter("TVP_Integer");
}
编辑:
如果您不能更改存储过程,那么您可以传递一个参数对象数组来执行,它将为数组中的每一项运行相同的存储过程。
来自文档的示例:
var affectedRows = connection.Execute(sql,
new[]
{
new {Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_1"},
new {Kind = InvoiceKind.WebInvoice, Code = "Many_Insert_2"},
new {Kind = InvoiceKind.StoreInvoice, Code = "Many_Insert_3"}
},
commandType: CommandType.StoredProcedure
);
My.Result.Show(affectedRows);
以上将运行存储过程 3 次,每次为传递给它的数组中的每个对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.