繁体   English   中英

在循环中使用时,连接在 dapper UOW 中为 null

[英]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 次,每次为传递给它的数组中的每个对象。

https://dapper-tutorial.net/execute#example---执行存储过程

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM