RepositoryBase - lobodava/artisan-orm GitHub Wiki
RepositoryBase is the base class for custom repositories. It uses one SqlConnection and attaches its current SqlTransaction to commands created by inherited methods. In the source being prepared for 4.1.0, connection ownership depends on the constructor: a connection-string repository owns its new connection; a repository constructed with an external transaction borrows that transaction's existing connection.
public class UserRepository : RepositoryBase
{
public UserRepository(string connectionString) : base(connectionString) { }
}-
Connection management: an owned
SqlConnectionstarts closed. Individual read/execute operations open it when necessary and close it if they opened it. A borrowed transaction uses its already-open connection. Repository disposal disposes owned resources and only detaches borrowed resources. -
Three
SqlCommandinitialization entry points —GetByCommand,RunCommand,ExecuteCommand. See SqlCommand initialization for the differences. -
Read shortcuts —
ReadTo<T>,ReadToList<T>,ReadAs<T>,ReadToArray<T>,ReadToDictionary<TKey,TValue>,ReadToTree<T>,ReadToObjectRows<T>, and the multi-result-setReadToLists<T1, T2[, T3[, T4]]>. All of them have async siblings and most accept eitherparams SqlParameter[]orAction<SqlCommand>for parameter setup. See Read methods. -
Write shortcuts —
Execute(...)/ExecuteAsync(...)for stored procedures or text batches with optional return value, plusBulkCopy<T>/BulkCopyAs<T>for high-throughput inserts. -
Transactions — both manual-commit (
BeginTransaction) and auto-commit (RunInTransaction), each with isolation-level overloads and async variants. See Transactions.
A repository instance uses one connection and mutable transaction state, so it is not safe to share across concurrent operations. Treat one repository as one unit of work:
-
ASP.NET Core / DI containers — register as
Scopedand inject. The container disposes the repository at the end of the HTTP request automatically. See Using Artisan.Orm in ASP.NET Core. -
Console apps and scripts —
using var repo = new UserRepository(connStr);. -
Background workers without a DI scope —
using var scope = _scopeFactory.CreateScope(); var repo = scope.ServiceProvider.GetRequiredService<MyRepo>();.
public RepositoryBase(string connectionString);
public RepositoryBase(SqlTransaction? transaction, string connectionString);With a non-null transaction, the second overload uses transaction.Connection, even if the supplied connection string describes another server or database. The string remains available as ConnectionString; it does not select a new connection in this case. With a null transaction, this overload creates an owned connection just like the first constructor.
The external transaction and connection remain caller-owned. Disposing or asynchronously disposing a borrowing repository does not commit, roll back, close, or dispose either resource. The constructor rejects a completed or disposed transaction whose connection is no longer available. BeginTransaction* and RunInTransaction* reject an already attached transaction; they are not savepoint helpers. The ownership choice is made by the constructor, so assigning the public Transaction property on an independently created repository is not a substitute for this constructor.
For sharing one active transaction between repositories, see the external-transaction example. These fixes describe the upcoming 4.1.0 source contract, not a guarantee about older packages.
public class RepositoryBase : IDisposable, IAsyncDisposable
{
public SqlConnection? Connection { get; } // nullable, disposed-aware
public string ConnectionString { get; }
public SqlTransaction? Transaction { get; set; }
// SqlCommand initialization
public T GetByCommand<T>(Func<SqlCommand, T> func);
public Task<T> GetByCommandAsync<T>(Func<SqlCommand, Task<T>> funcAsync);
public void RunCommand(Action<SqlCommand> action);
public int ExecuteCommand(Action<SqlCommand> action);
// ... + Async / CancellationToken variants
// Read families
public T? ReadTo<T> (string sql, params SqlParameter[] sqlParameters);
public IList<T> ReadToList<T> (string sql, params SqlParameter[] sqlParameters);
public T[] ReadToArray<T> (string sql, params SqlParameter[] sqlParameters);
public ObjectRows ReadToObjectRows<T>(...);
public IDictionary<TKey, TValue> ReadToDictionary<TKey, TValue>(...);
public T? ReadToTree<T>(...) where T : class, INode<T>;
public (IList<T1>, IList<T2>) ReadToLists<T1, T2>(...);
// ... + ReadAs* (auto-mapping) siblings, all with Async variants
// Write
public int Execute(string sql, params SqlParameter[] sqlParameters);
public int BulkCopy<T> (IEnumerable<T> rows, string destinationTable, ...);
public int BulkCopyAs<T> (IEnumerable<T> rows, string destinationTable, ...);
// Transactions
public void BeginTransaction(Action<SqlTransaction> action);
public void RunInTransaction(Action<SqlTransaction> action);
// ... + IsolationLevel and Async overloads
}See also: