Example #1
0
 /// <summary>
 /// Gets the identity <see cref="DbField"/> object.
 /// </summary>
 /// <param name="request">The request object.</param>
 /// <returns>The identity <see cref="DbField"/> object.</returns>
 private static DbField GetIdentityField(BaseRequest request)
 {
     if (request.Type != null && request.Type != typeof(object))
     {
         var identityProperty = IdentityCache.Get(request.Type);
         if (identityProperty != null)
         {
             var primaryProperty = PrimaryCache.Get(request.Type);
             var isPrimary       = false;
             if (primaryProperty != null)
             {
                 isPrimary = string.Equals(primaryProperty.GetMappedName(), identityProperty.GetMappedName(), StringComparison.OrdinalIgnoreCase);
             }
             return(new DbField(identityProperty.GetMappedName(),
                                isPrimary,
                                true,
                                false,
                                identityProperty.PropertyInfo.PropertyType,
                                null,
                                null,
                                null,
                                null));
         }
     }
     return(DbFieldCache.Get(request.Connection, request.Name, request.Transaction)?.FirstOrDefault(f => f.IsIdentity));
 }
Example #2
0
 /// <summary>
 /// Gets a value whether the current property is a primary property.
 /// </summary>
 /// <returns>True if the current property is a primary.</returns>
 public bool?IsPrimary()
 {
     if (isPrimary != null)
     {
         return(isPrimary);
     }
     return(isPrimary = PrimaryCache.Get(GetDeclaringType()) != null);
 }
Example #3
0
        /// <summary>
        /// Gets a value whether the current property is a primary property.
        /// </summary>
        /// <returns>True if the current property is a primary.</returns>
        public bool?IsPrimary()
        {
            if (m_isPrimary != null)
            {
                return(m_isPrimary);
            }

            // Get the value from the cache
            return(m_isPrimary = PrimaryCache.Get(GetDeclaringType()) != null);
        }
Example #4
0
 /// <summary>
 /// Gets the identity <see cref="DbField"/> object.
 /// </summary>
 /// <param name="request">The request object.</param>
 /// <returns>The identity <see cref="DbField"/> object.</returns>
 private static DbField GetIdentityField(BaseRequest request)
 {
     if (request.Type != null && request.Type != typeof(object))
     {
         var identityProperty = IdentityCache.Get(request.Type);
         if (identityProperty != null)
         {
             var primaryPropery = PrimaryCache.Get(request.Type);
             var isPrimary      = false;
             if (primaryPropery != null)
             {
                 isPrimary = primaryPropery.GetUnquotedMappedName().ToLower() == identityProperty.GetUnquotedMappedName().ToLower();
             }
             return(new DbField(identityProperty.GetUnquotedMappedName(), isPrimary, true, false,
                                identityProperty.PropertyInfo.PropertyType, null, null, null));
         }
     }
     return(DbFieldCache.Get(request.Connection, request.Name)?.FirstOrDefault(f => f.IsIdentity));
 }
        /// <summary>
        /// Selecting data from Sql with Sql IN clause usually requires 1 Parameter for every value, and this result in
        /// safe Sql Queries, but there is a limit of 2100 parameters on a Sql Command.  This method provides a safe
        /// alternative implementation that is highly performant for large data sets using a list of int values (e.g Ids).
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="sqlConnection"></param>
        /// <param name="idList"></param>
        /// <param name="filterFieldName"></param>
        /// <param name="tableName"></param>
        /// <param name="fields"></param>
        /// <param name="orderBy"></param>
        /// <param name="hints"></param>
        /// <param name="cacheKey"></param>
        /// <param name="cacheItemExpiration"></param>
        /// <param name="commandTimeout"></param>
        /// <param name="transaction"></param>
        /// <param name="logTrace"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="cache"></param>
        /// <returns></returns>
        public static async Task <IEnumerable <TEntity> > QueryBulkResultsByIdAsync <TEntity>(
            this SqlConnection sqlConnection,
            IEnumerable <int> idList,
            string filterFieldName           = null,
            string tableName                 = null,
            IEnumerable <Field> fields       = null,
            IEnumerable <OrderField> orderBy = null,
            string hints                        = null,
            string cacheKey                     = null,
            int?cacheItemExpiration             = null,
            int?commandTimeout                  = null,
            IDbTransaction transaction          = null,
            ICache cache                        = null,
            Action <string> logTrace            = null,
            CancellationToken cancellationToken = default
            ) where TEntity : class
        {
            var connection = sqlConnection ?? throw new ArgumentNullException(nameof(sqlConnection));

            var timer = Stopwatch.StartNew();

            Field filterField;

            if (string.IsNullOrWhiteSpace(filterFieldName))
            {
                //Attempt to dynamically resolve the Filter Field as the Identity or Primary Key field (if the field is a Numeric Type)!
                var classProp = IdentityCache.Get <TEntity>() ?? PrimaryCache.Get <TEntity>();
                if (classProp == null || !classProp.PropertyInfo.PropertyType.IsNumericType())
                {
                    throw new ArgumentException(
                              $"The filter field name was not specified and an Int Id could not be dynamically resolved from the Identity or Primary Key properties for the type [{typeof(TEntity).Name}]",
                              nameof(filterFieldName)
                              );
                }

                filterField = new Field(classProp.GetMappedName());
            }
            else
            {
                //If Specified then we use the Filter Field Name specified and attempt to resolve it on the Model!
                filterField = new Field(PropertyMappedNameCache.Get <TEntity>(filterFieldName) ?? filterFieldName);
            }

            var dbTableName = string.IsNullOrWhiteSpace(tableName)
                ? ClassMappedNameCache.Get <TEntity>()
                : tableName;

            //Ensure we have default fields; default is to include All Fields...
            var fieldsList = fields?.ToList();

            var selectFields = fieldsList?.Any() == true
                ? fieldsList
                : FieldCache.Get <TEntity>();

            //Retrieve only the select fields that are valid for the Database query!
            //NOTE: We guard against duplicate values as a convenience.
            var validSelectFields = await connection
                                    .GetValidatedDbFieldsAsync(dbTableName, selectFields.Distinct())
                                    .ConfigureAwait(false);

            var dbSetting = connection.GetDbSetting();

            var query = new QueryBuilder()
                        .Clear()
                        .Select().FieldsFrom(validSelectFields, dbSetting)
                        .From().TableNameFrom(dbTableName, dbSetting).WriteText("data")
                        .WriteText("INNER JOIN STRING_SPLIT(@StringSplitCsvValues, ',') split")
                        .On().WriteText("(data.").FieldFrom(filterField).WriteText("= split.value)")
                        .OrderByFrom(orderBy, dbSetting)
                        .HintsFrom(hints)
                        .End();

            var commandText   = query.GetString();
            var commandParams = new { StringSplitCsvValues = idList.ToCsvString(false) };

            logTrace?.Invoke($"Query: {commandText}");
            logTrace?.Invoke($"Query Param @StringSplitCsvValues: {commandParams.StringSplitCsvValues}");

            await connection.EnsureOpenAsync(cancellationToken : cancellationToken);

            logTrace?.Invoke($"DB Connection Established in: {timer.ToElapsedTimeDescriptiveFormat()}");

            //By creating a View Model of the data we are interested in we can easily query the View
            //  and teh complex many-to-many join is now encapsulated for us in the SQL View...
            var results = await connection.ExecuteQueryAsync <TEntity>(
                commandText,
                commandParams,
                commandType : CommandType.Text,
                commandTimeout : commandTimeout,
                transaction : transaction,
                cancellationToken : cancellationToken,
                cacheKey : cacheKey,
                cacheItemExpiration : cacheItemExpiration,
                cache : cache
                ).ConfigureAwait(false);

            logTrace?.Invoke($"Query Execution Completed in: {timer.ToElapsedTimeDescriptiveFormat()}");

            return(results);
        }