/// <summary> /// Uses <see cref="IRelationalDbStorage"/> with <see cref="DbExtensions.ReflectionParameterProvider{T}(System.Data.IDbCommand, T, IReadOnlyDictionary{string, string})">DbExtensions.ReflectionParameterProvider</see>. /// </summary> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="storage">The storage to use.</param> /// <param name="query">Executes a given statement. Especially intended to use with <em>SELECT</em> statement, but works with other queries too.</param> /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param> /// <returns>A list of objects as a result of the <see paramref="query"/>.</returns> public static Task <IEnumerable <TResult> > ReadAsync <TResult>( this IRelationalDbStorage storage, string query, CancellationToken cancellationToken = default) { return(ReadAsync <TResult>(storage, query, null, cancellationToken)); }
/// <summary> /// A simplified version of <see cref="IRelationalDbStorage.ReadAsync{TResult}"/> /// </summary> /// <param name="storage"></param> /// <param name="query"></param> /// <param name="selector"></param> /// <param name="parameterProvider"></param> /// <typeparam name="TResult"></typeparam> /// <returns></returns> public static Task <IEnumerable <TResult> > ReadAsync <TResult>( this IRelationalDbStorage storage, string query, Func <IDataRecord, TResult> selector, Action <IDbCommand> parameterProvider) => storage.ReadAsync( query, parameterProvider, (record, i, cancellationToken) => Task.FromResult(selector(record)));
public MySqlDomainEventStateBackend( IRelationalDbStorageFactory factory, ILogger <MySqlDomainEventStateBackend> logger, ITypeResolver typeResolver, IOptions <MySqlStateBackendOptions> options, IBinarySerializer binarySerializer) { _logger = logger; _db = factory.CreateRelationalDbStorage(DatabaseScheme.StateDb); _typeResolver = typeResolver; _binarySerializer = binarySerializer; _options = options.Value; }
public MySqlAggregateRootCheckpointStateBackend( IRelationalDbStorageFactory storageFactory, ILoggerFactory loggerFactory, ITypeResolver typeResolver, IOptions <MySqlStateBackendOptions> options, IBinarySerializer binarySerializer) { _logger = loggerFactory.CreateLogger(typeof(MySqlAggregateRootCheckpointStateBackend <TPayload>)); _db = storageFactory.CreateRelationalDbStorage(DatabaseScheme.StateDb); _typeResolver = typeResolver; _binarySerializer = binarySerializer; _options = options.Value; }
/// <summary> /// Uses <see cref="IRelationalDbStorage"/> with <see cref="DbExtensions.ReflectionSelector{TResult}(System.Data.IDataRecord)"/>. /// </summary> /// <param name="storage">The storage to use.</param> /// <param name="query">Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.</param> /// <param name="parameters">Adds parameters to the query. Parameter names must match those defined in the query.</param> /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param> /// <returns>Affected rows count.</returns> /// <example>This uses reflection to provide parameters to an execute /// query that reads only affected rows count if available. /// <code> /// //Here reflection (<seealso cref="DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})"/>) /// is used to match parameter names as well as to read back the results (<seealso cref="DbExtensions.ReflectionSelector{TResult}(IDataRecord)"/>). /// var query = "IF NOT EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tname) CREATE TABLE Test(Id INT PRIMARY KEY IDENTITY(1, 1) NOT NULL);" /// await db.ExecuteAsync(query, new { tname = "test_table" }); /// </code> /// </example> public static Task <int> ExecuteAsync( this IRelationalDbStorage storage, string query, object parameters, CancellationToken cancellationToken = default) { return(storage.ExecuteAsync(query, command => { if (parameters != null) { command.ReflectionParameterProvider(parameters); } }, cancellationToken)); }
/// <summary> /// Uses <see cref="IRelationalDbStorage"/> with <see cref="DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})"/>. /// </summary> /// <typeparam name="TResult">The type of the result.</typeparam> /// <param name="storage">The storage to use.</param> /// <param name="query">Executes a given statement. Especially intended to use with <em>SELECT</em> statement, but works with other queries too.</param> /// <param name="parameters">Adds parameters to the query. Parameter names must match those defined in the query.</param> /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param> /// <returns>A list of objects as a result of the <see paramref="query"/>.</returns> /// <example>This uses reflection to read results and match the parameters. /// <code> /// //This struct holds the return value in this example. /// public struct Information /// { /// public string TABLE_CATALOG { get; set; } /// public string TABLE_NAME { get; set; } /// } /// /// //Here reflection (<seealso cref="DbExtensions.ReflectionParameterProvider{T}(IDbCommand, T, IReadOnlyDictionary{string, string})"/>) /// is used to match parameter names as well as to read back the results (<seealso cref="DbExtensions.ReflectionSelector{TResult}(IDataRecord)"/>). /// var query = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @tname;"; /// IEnumerable<Information> informationData = await db.ReadAsync<Information>(query, new { tname = 200000 }); /// </code> /// </example> public static Task <IEnumerable <TResult> > ReadAsync <TResult>( this IRelationalDbStorage storage, string query, object parameters, CancellationToken cancellationToken = default) { return(storage.ReadAsync(query, command => { if (parameters != null) { command.ReflectionParameterProvider(parameters); } }, (selector, resultSetCount, token) => Task.FromResult(selector.ReflectionSelector <TResult>()), cancellationToken)); }
/// <summary> /// Uses <see cref="IRelationalDbStorage"/> with <see cref="DbExtensions.ReflectionSelector{TResult}(System.Data.IDataRecord)"/>. /// </summary> /// <param name="storage">The storage to use.</param> /// <param name="query">Executes a given statement. Especially intended to use with <em>INSERT</em>, <em>UPDATE</em>, <em>DELETE</em> or <em>DDL</em> queries.</param> /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param> /// <returns>Affected rows count.</returns> public static Task <int> ExecuteAsync( this IRelationalDbStorage storage, string query, CancellationToken cancellationToken = default) => ExecuteAsync(storage, query, null, cancellationToken);
public MySqlTransferringReadDbSynchronizer(IRelationalDbStorageFactory db) { _db = db.CreateRelationalDbStorage(DatabaseScheme.ReadDb); }
/// <summary> /// If the underlying ADO.NET implementation is known to be synchronous. /// </summary> /// <param name="storage">The storage used.</param> /// <returns></returns> public static bool IsSynchronousAdoNetImplementation(this IRelationalDbStorage storage) { // Currently the assumption is all but MySQL are asynchronous. return(IsSynchronousAdoNetImplementation(storage.InvariantName)); }
public MySqWithdrawReadDbSynchronizer(IRelationalDbStorageFactory db) { _db = db.CreateRelationalDbStorage(DatabaseScheme.ReadDb); }
public MySqlBankAccountRepository(IRelationalDbStorageFactory db) { _db = db.CreateRelationalDbStorage(DatabaseScheme.StateDb); }
public MySqlBankAccountQueryService(IRelationalDbStorageFactory db) { _db = db.CreateRelationalDbStorage(DatabaseScheme.ReadDb); }
/// <summary> /// If the underlying storage supports streaming natively. /// </summary> /// <param name="storage">The storage used.</param> /// <returns><em>TRUE</em> if streaming is supported natively. <em>FALSE</em> otherwise.</returns> public static bool SupportsStreamNatively(this IRelationalDbStorage storage) => SupportsStreamNatively(storage.InvariantName);
/// <summary> /// If the underlying storage supports cancellation or not. /// </summary> /// <param name="storage">The storage used.</param> /// <returns><em>TRUE</em> if cancellation is supported. <em>FALSE</em> otherwise.</returns> public static bool SupportsCommandCancellation(this IRelationalDbStorage storage) => SupportsCommandCancellation(storage.InvariantName);
/// <summary> /// Returns a native implementation of <see cref="DbDataReader.GetStream(int)"/> for those providers /// which support it. Otherwise returns a chunked read using <see cref="DbDataReader.GetBytes(int, long, byte[], int, int)"/>. /// </summary> /// <param name="reader">The reader from which to return the stream.</param> /// <param name="ordinal">The ordinal column for which to return the stream.</param> /// <param name="storage">The storage that gives the invariant.</param> /// <returns></returns> public static Stream GetStream(this DbDataReader reader, int ordinal, IRelationalDbStorage storage) => storage.SupportsStreamNatively() ? reader.GetStream(ordinal) : new RelationalDownloadStream(reader, ordinal);
/// <summary> /// Executes a multi-record insert query clause with <em>SELECT UNION ALL</em>. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="storage">The storage to use.</param> /// <param name="tableName">The table name to against which to execute the query.</param> /// <param name="parameters">The parameters to insert.</param> /// <param name="cancellationToken">The cancellation token. Defaults to <see cref="CancellationToken.None"/>.</param> /// <param name="nameMap">If provided, maps property names from <typeparamref name="T"/> to ones provided in the map.</param> /// <param name="onlyOnceColumns">If given, SQL parameter values for the given <typeparamref name="T"/> property types are generated only once. Effective only when <paramref name="useSqlParams"/> is <em>TRUE</em>.</param> /// <param name="useSqlParams"><em>TRUE</em> if the query should be in parameterized form. <em>FALSE</em> otherwise.</param> /// <returns>The rows affected.</returns> public static Task <int> ExecuteMultipleInsertIntoAsync <T>( this IRelationalDbStorage storage, string tableName, IEnumerable <T> parameters, CancellationToken cancellationToken = default, IReadOnlyDictionary <string, string> nameMap = null, IEnumerable <string> onlyOnceColumns = null, bool useSqlParams = true) { if (string.IsNullOrWhiteSpace(tableName)) { throw new ArgumentException("The name must be a legal SQL table name", nameof(tableName)); } if (parameters == null) { throw new ArgumentNullException(nameof(parameters)); } var storageConstants = DbConstantsStore.GetDbConstants(storage.InvariantName); var startEscapeIndicator = storageConstants.StartEscapeIndicator; var endEscapeIndicator = storageConstants.EndEscapeIndicator; //SqlParameters map is needed in case the query needs to be parameterized in order to avoid two //reflection passes as first a query needs to be constructed and after that when a database //command object has been created, parameters need to be provided to them. var sqlParameters = new Dictionary <string, object>(); const string insertIntoValuesTemplate = "INSERT INTO {0} ({1}) SELECT {2};"; var columns = string.Empty; var values = new List <string>(); if (parameters.Any()) { //Type and property information are the same for all of the objects. //The following assumes the property names will be retrieved in the same //order as is the index iteration done. var onlyOnceRow = new List <string>(); var properties = parameters.First().GetType().GetProperties(); columns = string.Join(",", nameMap == null ? properties.Select(pn => $"{startEscapeIndicator}{pn.Name}{endEscapeIndicator}") : properties.Select(pn => $"{startEscapeIndicator}{(nameMap.ContainsKey(pn.Name) ? nameMap[pn.Name] : pn.Name)}{endEscapeIndicator}")); if (onlyOnceColumns != null && onlyOnceColumns.Any()) { var onlyOnceProperties = properties.Where(pn => onlyOnceColumns.Contains(pn.Name)).Select(pn => pn).ToArray(); var onlyOnceData = parameters.First(); foreach (var t in onlyOnceProperties) { var currentProperty = t; var parameterValue = currentProperty.GetValue(onlyOnceData, null); if (useSqlParams) { var parameterName = $"@{(nameMap.ContainsKey(t.Name) ? nameMap[t.Name] : t.Name)}"; onlyOnceRow.Add(parameterName); sqlParameters.Add(parameterName, parameterValue); } else { onlyOnceRow.Add(string.Format(AdoNetFormatProvider, "{0}", parameterValue)); } } } var dataRows = new List <string>(); var multiProperties = onlyOnceColumns == null ? properties : properties.Where(pn => !onlyOnceColumns.Contains(pn.Name)).Select(pn => pn).ToArray(); var parameterCount = 0; foreach (var row in parameters) { foreach (var currentProperty in multiProperties) { var parameterValue = currentProperty.GetValue(row, null); if (useSqlParams) { var parameterName = string.Format(IndexedParameterTemplate, parameterCount); dataRows.Add(parameterName); sqlParameters.Add(parameterName, parameterValue); ++parameterCount; } else { dataRows.Add(string.Format(AdoNetFormatProvider, "{0}", parameterValue)); } } values.Add($"{string.Join(",", onlyOnceRow.Concat(dataRows))}"); dataRows.Clear(); } } var query = string.Format(insertIntoValuesTemplate, tableName, columns, string.Join(storageConstants.UnionAllSelectTemplate, values)); return(storage.ExecuteAsync(query, command => { if (!useSqlParams) { return; } foreach (var sp in sqlParameters) { var p = command.CreateParameter(); p.ParameterName = sp.Key; p.Value = sp.Value ?? DBNull.Value; p.Direction = ParameterDirection.Input; command.Parameters.Add(p); } }, cancellationToken)); }
public MySqlBankAccountReadDbSynchronizer(IRelationalDbStorageFactory db) { _db = db.CreateRelationalDbStorage(DatabaseScheme.ReadDb); }