Exemple #1
0
        internal static bool ExecuteObjectExist(this DbHelper dbHelper, IRepositoryConventions conventions, DbCommand command, object obj)
        {
            Guard.NotNull(dbHelper, nameof(dbHelper));
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(command, nameof(command));
            Guard.NotNull(obj, nameof(obj));

            var entityType             = obj.GetType();
            var tableName              = conventions.GetTableName(entityType);
            var primaryKeyPropertyInfo = conventions.GetPrimaryKeyPropertyInfos(entityType).First();
            var primaryKeyColumnName   = conventions.GetColumnName(primaryKeyPropertyInfo);

            command.CommandText = $"SELECT * FROM [{tableName}]\nWHERE {primaryKeyColumnName} = @{primaryKeyColumnName}";
            command.CommandType = CommandType.Text;
            command.Parameters.Clear();
            command.AddParameter($"@{primaryKeyColumnName}", primaryKeyPropertyInfo.GetValue(obj, null));

            var existInDb = false;

            using (var reader = dbHelper.ExecuteReader(command))
            {
                while (reader.Read())
                {
                    existInDb = true;

                    break;
                }
            }

            return(existInDb);
        }
Exemple #2
0
        /// <summary>
        /// Defaults this instance.
        /// </summary>
        /// <param name="conventions">The configurable conventions.</param>
        /// <returns>The default fetch strategy.</returns>
        public static IFetchQueryStrategy <T> Default([NotNull] IRepositoryConventions conventions)
        {
            Guard.NotNull(conventions, nameof(conventions));

            var mainTableProperties = typeof(T).GetRuntimeProperties().ToList();

            // Assumes we want to perform a join when the navigation property from the primary table has also a navigation property of
            // the same type as the primary table
            // Only do a join when the primary table has a foreign key property for the join table
            var paths = mainTableProperties
                        .Where(x => x.IsComplex() && conventions.GetPrimaryKeyPropertyInfos(x.PropertyType).Any())
                        .Select(x => x.Name)
                        .ToList();

            var fetchStrategy = new FetchQueryStrategy <T>();

            if (paths.Count > 0)
            {
                foreach (var path in paths)
                {
                    fetchStrategy.Fetch(path);
                }
            }

            return(fetchStrategy);
        }
        public static void CreateInsertStatement(IRepositoryConventions conventions, object entity, out string sql, out Dictionary <string, object> parameters)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(entity, nameof(entity));

            parameters = new Dictionary <string, object>();

            var entityType = entity.GetType();
            var tableName  = conventions.GetTableName(entityType);

            var primaryKeyPropertyInfos = conventions.GetPrimaryKeyPropertyInfos(entityType).ToList();
            var properties = GetProperties(conventions, entityType);

            if (primaryKeyPropertyInfos.Count == 1)
            {
                var primaryKeyPropertyInfo = primaryKeyPropertyInfos.First();
                var primaryKeyColumnName   = conventions.GetColumnName(primaryKeyPropertyInfo);

                if (conventions.IsColumnIdentity(primaryKeyPropertyInfo))
                {
                    properties.Remove(primaryKeyColumnName);
                    parameters.Add($"@{primaryKeyColumnName}", primaryKeyPropertyInfo.GetValue(entity, null));
                }
            }

            foreach (var x in properties)
            {
                parameters.Add($"@{x.Key}", x.Value.GetValue(entity, null));
            }

            var columnNames = string.Join(", ", properties.Select(x => x.Key)).TrimEnd();
            var values      = string.Join(", ", properties.Select(x => $"@{x.Key}")).TrimEnd();

            sql = $"INSERT INTO [{tableName}] ({columnNames}){Environment.NewLine}VALUES ({values})";
        }
        /// <summary>
        /// Maps each element to a new form.
        /// </summary>
        /// <param name="reader">The data reader used for transforming each element.</param>
        /// <param name="conventions">The configurable conventions.</param>
        /// <returns>The new projected element form.</returns>
        public T Map([NotNull] IDataReader reader, [NotNull] IRepositoryConventions conventions)
        {
            Guard.NotNull(reader, nameof(reader));
            Guard.NotNull(conventions, nameof(conventions));

            var properties = GetProperties(conventions);
            var entity     = Activator.CreateInstance <T>();

            for (var i = 0; i < reader.FieldCount; i++)
            {
                var name  = reader.GetName(i);
                var value = reader[name];

                if (value == DBNull.Value)
                {
                    value = null;
                }

                if (properties.ContainsKey(name))
                {
                    if (!reader.IsDBNull(reader.GetOrdinal(name)))
                    {
                        var pi = properties[name];

                        pi.SetValue(entity, value);
                    }
                }
            }

            return(entity);
        }
Exemple #5
0
 public Customer Map(IDataReader reader, IRepositoryConventions conventions)
 {
     return(new Customer()
     {
         Id = reader.GetInt32(0),
         Name = reader.GetString(1)
     });
 }
        /// <summary>
        /// Returns the option instance with a configured conventions.
        /// </summary>
        /// <param name="conventions">The configurable conventions.</param>
        /// <returns>The same option instance.</returns>
        public RepositoryOptions With([NotNull] IRepositoryConventions conventions)
        {
            var clone = Clone();

            clone._conventions = Guard.NotNull(conventions, nameof(conventions));

            return(clone);
        }
Exemple #7
0
        /// <summary>
        /// Gets a collection of primary keys for the specified type.
        /// </summary>
        /// <param name="source">The repository conventions.</param>
        /// <param name="type">The type.</param>
        /// <returns>The collection of primary keys for the specified type.</returns>
        public static PropertyInfo[] GetPrimaryKeyPropertyInfos([NotNull] this IRepositoryConventions source, [NotNull] Type type)
        {
            Guard.NotNull(type, nameof(type));

            var result = EnsureCallback(
                source.PrimaryKeysCallback,
                nameof(source.PrimaryKeysCallback))(type) ?? new PropertyInfo[0];

            return(result);
        }
Exemple #8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="RepositoryOptions" /> class.
        /// </summary>
        /// <param name="options">The repository options to clone.</param>
        public RepositoryOptions([NotNull] IRepositoryOptions options)
        {
            Guard.NotNull(options, nameof(options));

            _interceptors    = options.Interceptors.ToDictionary(x => x.Key, x => x.Value);
            _cachingProvider = options.CachingProvider;
            _loggerProvider  = options.LoggerProvider;
            _contextFactory  = options.ContextFactory;
            _conventions     = options.Conventions;
        }
        private static Dictionary <string, PropertyInfo> GetProperties(IRepositoryConventions conventions, Type entityType)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(entityType, nameof(entityType));

            return(entityType
                   .GetRuntimeProperties()
                   .Where(x => x.IsPrimitive() && conventions.IsColumnMapped(x))
                   .OrderBy(conventions.GetColumnOrderOrDefault)
                   .ToDictionary(conventions.GetColumnName, x => x));
        }
 public static void CreateSelectStatement <T>(IRepositoryConventions conventions, IQueryOptions <T> options, out string sql, out Dictionary <string, object> parameters)
 {
     CreateSelectStatement <T>(
         conventions,
         options,
         false,
         out sql,
         out parameters,
         out var navigationProperties,
         out var getPropertyFromColumnAliasCallback);
 }
 public static void CreateSelectStatement <T>(IRepositoryConventions conventions, IQueryOptions <T> options, out string sql, out Dictionary <string, object> parameters, out Dictionary <Type, Dictionary <string, PropertyInfo> > navigationProperties, out Func <string, Type> getTableTypeByColumnAliasCallback)
 {
     CreateSelectStatement <T>(
         conventions,
         options,
         true,
         out sql,
         out parameters,
         out navigationProperties,
         out getTableTypeByColumnAliasCallback);
 }
Exemple #12
0
        /// <summary>
        /// Throws an exception if the specified entity type has an invalid primary key definition.
        /// </summary>
        /// <param name="source">The configurable conventions.</param>
        internal static void ThrowsIfInvalidPrimaryKeyDefinition <T>([NotNull] this IRepositoryConventions source) where T : class
        {
            var definedKeyInfos = source.GetPrimaryKeyPropertyInfos <T>();

            if (!definedKeyInfos.Any())
            {
                throw new InvalidOperationException(string.Format(
                                                        Resources.EntityRequiresPrimaryKey,
                                                        typeof(T).FullName));
            }
        }
Exemple #13
0
        public Mapper(IRepositoryConventions conventions)
        {
            _conventions = Guard.NotNull(conventions, nameof(conventions));

            _properties = typeof(T).GetRuntimeProperties()
                          .Where(x => x.IsPrimitive() && _conventions.IsColumnMapped(x))
                          .OrderBy(_conventions.GetColumnOrderOrDefault)
                          .ToDictionary(_conventions.GetColumnName, x => x);

            _navigationProperties = new Dictionary <Type, Dictionary <string, PropertyInfo> >();
        }
Exemple #14
0
        public static bool IsColumnIdentity([NotNull] IRepositoryConventions conventions, [NotNull] PropertyInfo pi)
        {
            Guard.NotNull(pi, nameof(pi));

            if (!_isColumnIdentityCache.TryGetValue(pi, out bool result))
            {
                result = IsColumnIdentityCore(conventions, pi);
                _isColumnIdentityCache.TryAdd(pi, result);
            }

            return(result);
        }
Exemple #15
0
        private static bool IsColumnIdentityCore(IRepositoryConventions conventions, PropertyInfo pi)
        {
            var databaseGeneratedAttribute = pi.GetCustomAttribute <DatabaseGeneratedAttribute>();

            if (databaseGeneratedAttribute == null)
            {
                var primaryKeyPropertyInfos = conventions.GetPrimaryKeyPropertyInfos(pi.DeclaringType);

                return((primaryKeyPropertyInfos.Length == 1) && primaryKeyPropertyInfos.First().Name.Equals(pi.Name));
            }

            return(databaseGeneratedAttribute.DatabaseGeneratedOption == DatabaseGeneratedOption.Identity);
        }
Exemple #16
0
        public static int?GetColumnOrder([NotNull] IRepositoryConventions conventions, [NotNull] PropertyInfo pi)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(pi, nameof(pi));

            if (!_columnOrderCache.TryGetValue(pi, out int?result))
            {
                result = GetColumnOrderCore(conventions, pi);
                _columnOrderCache.TryAdd(pi, result);
            }

            return(result);
        }
        private Dictionary <string, PropertyInfo> GetProperties([NotNull] IRepositoryConventions conventions)
        {
            Guard.NotNull(conventions, nameof(conventions));

            if (_propertiesMapping == null || _propertiesMapping.Count == 0)
            {
                _propertiesMapping = typeof(T).GetRuntimeProperties()
                                     .Where(x => x.IsPrimitive() && conventions.IsColumnMapped(x))
                                     .ToDictionary(conventions.GetColumnName, x => x);
            }

            return(_propertiesMapping);
        }
Exemple #18
0
        /// <summary>
        /// Gets a collection of primary keys for the specified type.
        /// </summary>
        /// <param name="source">The repository conventions.</param>
        /// <param name="type">The type.</param>
        /// <returns>The collection of primary keys for the specified type.</returns>
        public static PropertyInfo[] GetPrimaryKeyPropertyInfos([NotNull] this IRepositoryConventions source, [NotNull] Type type)
        {
            EnsureOwner(source);
            Guard.NotNull(type, nameof(type));

            var store = _primaryKeyPropertyInfosCache.GetOrAdd(source.Owner, new ConcurrentDictionary <Type, PropertyInfo[]>());

            if (!store.TryGetValue(type, out var result))
            {
                store[type] = result = EnsureCallback(
                    source.PrimaryKeysCallback,
                    nameof(source.PrimaryKeysCallback))(type) ?? new PropertyInfo[0];
            }

            return(result);
        }
Exemple #19
0
        private static Type EnsureOwner([NotNull] IRepositoryConventions source)
        {
            Guard.NotNull(source, nameof(source));

            var owner = Guard.EnsureNotNull(
                source.Owner,
                string.Format("The conventions '{0}' cannot be null.", nameof(source.Owner)));

            if (!owner.ImplementsInterface(typeof(IRepositoryContext)))
            {
                throw new InvalidOperationException(string.Format(
                                                        "The conventions '{0}' is not an instance of type '{1}'.", nameof(source.Owner), typeof(IRepositoryContext).FullName));
            }

            return(owner);
        }
Exemple #20
0
        /// <summary>
        /// Determines whether the specified property is defined as identity.
        /// </summary>
        /// <param name="source">The configurable conventions.</param>
        /// <param name="pi">The property.</param>
        /// <returns><c>true</c> if column is defined as identity.; otherwise, <c>false</c>.</returns>
        public static bool IsColumnIdentity([NotNull] this IRepositoryConventions source, [NotNull] PropertyInfo pi)
        {
            EnsureOwner(source);
            Guard.NotNull(pi, nameof(pi));

            var store = _isColumnIdentityCallback.GetOrAdd(source.Owner, new ConcurrentDictionary <PropertyInfo, bool>());

            if (!store.TryGetValue(pi, out var result))
            {
                store[pi] = result = EnsureCallback(
                    source.IsColumnIdentityCallback,
                    nameof(source.IsColumnIdentityCallback))(pi);
            }

            return(result);
        }
Exemple #21
0
        /// <summary>
        /// Gets a column order for the specified property.
        /// </summary>
        /// <param name="source">The configurable conventions.</param>
        /// <param name="pi">The property.</param>
        /// <returns>The column order for the specified property.</returns>
        public static int?GetColumnOrder([NotNull] this IRepositoryConventions source, [NotNull] PropertyInfo pi)
        {
            EnsureOwner(source);
            Guard.NotNull(pi, nameof(pi));

            var store = _columnOrderCache.GetOrAdd(source.Owner, new ConcurrentDictionary <PropertyInfo, int?>());

            if (!store.TryGetValue(pi, out var result))
            {
                store[pi] = result = EnsureCallback(
                    source.ColumnOrderCallback,
                    nameof(source.ColumnOrderCallback))(pi);
            }

            return(result);
        }
Exemple #22
0
        /// <summary>
        /// Gets a table name for the specified type.
        /// </summary>
        /// <param name="source">The configurable conventions.</param>
        /// <param name="type">The type.</param>
        /// <returns>The table name for the specified type.</returns>
        public static string GetTableName([NotNull] this IRepositoryConventions source, [NotNull] Type type)
        {
            EnsureOwner(source);
            Guard.NotNull(type, nameof(type));

            var store = _tableNameCache.GetOrAdd(source.Owner, new ConcurrentDictionary <Type, string>());

            if (!store.TryGetValue(type, out var result))
            {
                store[type] = result = EnsureCallback(
                    source.TableNameCallback,
                    nameof(source.TableNameCallback))(type);
            }

            return(result);
        }
Exemple #23
0
        /// <summary>
        /// Gets a collection of foreign key properties that matches the specified foreign type.
        /// </summary>
        /// <param name="source">The repository conventions.</param>
        /// <param name="sourceType">The source type.</param>
        /// <param name="foreignType">The foreign type to match.</param>
        /// <returns>The collection of foreign key properties that matches the specified foreign type.</returns>
        public static PropertyInfo[] GetForeignKeyPropertyInfos([NotNull] this IRepositoryConventions source, [NotNull] Type sourceType, [NotNull] Type foreignType)
        {
            EnsureOwner(source);
            Guard.NotNull(sourceType, nameof(sourceType));
            Guard.NotNull(foreignType, nameof(foreignType));

            var store = _foreignKeyPropertyInfosCache.GetOrAdd(source.Owner, new ConcurrentDictionary <Tuple <Type, Type>, PropertyInfo[]>());
            var key   = Tuple.Create(sourceType, foreignType);

            if (!store.TryGetValue(key, out var result))
            {
                store[key] = result = EnsureCallback(
                    source.ForeignKeysCallback,
                    nameof(source.ForeignKeysCallback))(sourceType, foreignType) ?? new PropertyInfo[0];
            }

            return(result);
        }
        /// <summary>
        /// Throws an exception if the specified key type collection does not match the ones defined for the entity.
        /// </summary>
        /// <param name="source">The configurable conventions.</param>
        /// <param name="keyTypes">The key type collection to check against.</param>
        public static void ThrowsIfInvalidPrimaryKeyDefinition <T>([NotNull] this IRepositoryConventions source, [NotNull] params Type[] keyTypes) where T : class
        {
            Guard.NotNull(source, nameof(source));
            Guard.NotEmpty(keyTypes, nameof(keyTypes));

            var definedKeyInfos = source.GetPrimaryKeyPropertyInfos <T>().ToList();

            if (!definedKeyInfos.Any())
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
                                                                  Resources.EntityRequiresPrimaryKey,
                                                                  typeof(T).FullName));
            }

            if (definedKeyInfos.Count > 1)
            {
                var hasNoKeyOrdering = definedKeyInfos.Any(x =>
                {
                    var columnOrdering = source.GetColumnOrder(x);

                    if (!columnOrdering.HasValue)
                    {
                        return(true);
                    }

                    return(columnOrdering.Value <= 0);
                });

                if (hasNoKeyOrdering)
                {
                    throw new InvalidOperationException(string.Format(
                                                            Resources.UnableToDetermineCompositePrimaryKeyOrdering, typeof(T).FullName));
                }
            }

            var definedKeyTypes = definedKeyInfos
                                  .Select(x => x.PropertyType)
                                  .ToArray();

            if (keyTypes.Length != definedKeyTypes.Length || definedKeyTypes.Where((t, i) => t != keyTypes[i]).Any())
            {
                throw new InvalidOperationException(Resources.EntityPrimaryKeyTypesMismatch);
            }
        }
Exemple #25
0
        private static int?GetColumnOrderCore(IRepositoryConventions conventions, PropertyInfo pi)
        {
            var columnAttribute = pi.GetCustomAttribute <ColumnAttribute>();

            if (columnAttribute == null)
            {
                // Checks to see if the property is a primary key, and if so, try to give it the lowest ordering number
                var primerKeyPropertyInfos = conventions.GetPrimaryKeyPropertyInfos(pi.DeclaringType);

                if ((primerKeyPropertyInfos.Length == 1) && primerKeyPropertyInfos.First().Name.Equals(pi.Name))
                {
                    return(-1);
                }
            }
            else if (columnAttribute.Order > 0)
            {
                return(columnAttribute.Order);
            }

            return(null);
        }
Exemple #26
0
        public static PropertyInfo[] GetPrimaryKeyPropertyInfos([NotNull] IRepositoryConventions conventions, [NotNull] Type entityType)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(entityType, nameof(entityType));

            // Gets by checking the annotations
            var propertyInfos = entityType
                                .GetRuntimeProperties()
                                .Where(x => conventions.IsColumnMapped(x) && x.GetCustomAttribute <KeyAttribute>() != null)
                                .OrderBy(x =>
            {
                var columnAttribute = x.GetCustomAttribute <ColumnAttribute>();
                if (columnAttribute != null && columnAttribute.Order > 0)
                {
                    return(columnAttribute.Order);
                }

                return(int.MaxValue);
            })
                                .ToList();

            // Gets by naming convention
            if (!propertyInfos.Any())
            {
                foreach (var propertyName in GetDefaultPrimaryKeyNameChecks(entityType))
                {
                    var propertyInfo = entityType.GetTypeInfo().GetDeclaredProperty(propertyName);

                    if (propertyInfo != null && conventions.IsColumnMapped(propertyInfo))
                    {
                        propertyInfos.Add(propertyInfo);

                        break;
                    }
                }
            }

            return(propertyInfos.ToArray());
        }
        public static void CreateDeleteStatement(IRepositoryConventions conventions, object entity, out string sql, out Dictionary <string, object> parameters)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(entity, nameof(entity));

            parameters = new Dictionary <string, object>();

            var entityType = entity.GetType();
            var tableName  = conventions.GetTableName(entityType);

            var primaryKeyColumnNamesDict = conventions
                                            .GetPrimaryKeyPropertyInfos(entityType)
                                            .ToDictionary(conventions.GetColumnName, x => x);

            var condition = string.Join(" AND ", primaryKeyColumnNamesDict.Select(kv => "(" + kv.Key + " = @" + kv.Key + ")"));

            sql = $"DELETE FROM [{tableName}]{Environment.NewLine}WHERE ({condition})";

            foreach (var x in primaryKeyColumnNamesDict)
            {
                parameters.Add($"@{x.Key}", x.Value.GetValue(entity, null));
            }
        }
        public static void CreateUpdateStatement(IRepositoryConventions conventions, object entity, out string sql, out Dictionary <string, object> parameters)
        {
            Guard.NotNull(conventions, nameof(conventions));
            Guard.NotNull(entity, nameof(entity));

            parameters = new Dictionary <string, object>();

            var entityType = entity.GetType();
            var tableName  = conventions.GetTableName(entityType);

            var primaryKeyPropertyInfos   = conventions.GetPrimaryKeyPropertyInfos(entityType).ToList();
            var primaryKeyColumnNamesDict = primaryKeyPropertyInfos.ToDictionary(conventions.GetColumnName, x => x);
            var properties = GetProperties(conventions, entityType);

            if (primaryKeyPropertyInfos.Count == 1)
            {
                var primaryKeyPropertyInfo = primaryKeyPropertyInfos.First();
                var primaryKeyColumnName   = conventions.GetColumnName(primaryKeyPropertyInfo);

                if (conventions.IsColumnIdentity(primaryKeyPropertyInfo))
                {
                    properties.Remove(primaryKeyColumnName);
                    parameters.Add($"@{primaryKeyColumnName}", primaryKeyPropertyInfo.GetValue(entity, null));
                }
            }

            var values    = string.Join($",{Environment.NewLine}\t", properties.Select(x => x.Key + " = " + $"@{x.Key}"));
            var condition = string.Join(" AND ", primaryKeyColumnNamesDict.Select(kv => "(" + kv.Key + " = @" + kv.Key + ")"));

            sql = $"UPDATE [{tableName}]{Environment.NewLine}SET {values}{Environment.NewLine}WHERE ({condition})";

            foreach (var x in properties)
            {
                parameters.Add($"@{x.Key}", x.Value.GetValue(entity, null));
            }
        }
        /// <summary>
        /// Apply a sorting options to the specified entity's query.
        /// </summary>
        /// <returns>The entity's query with the applied options.</returns>
        public static IOrderedQueryable <T> ApplySortingOptions <T>([NotNull] this IQueryable <T> query, [NotNull] IRepositoryConventions conventions, [CanBeNull] IQueryOptions <T> options) where T : class
        {
            Guard.NotNull(query, nameof(query));

            var sorting = new Dictionary <string, SortOrder>();

            if (options != null)
            {
                sorting = options.SortingProperties.ToDictionary(x => x.Key, x => x.Value);
            }

            // Sorts on the composite key by default if no sorting is provided
            if (!sorting.Any())
            {
                foreach (var primaryKeyPropertyInfo in conventions.GetPrimaryKeyPropertyInfos <T>())
                {
                    sorting.Add(primaryKeyPropertyInfo.Name, SortOrder.Ascending);
                }
            }

            var primarySorting         = sorting.ElementAt(0);
            var primarySortingOrder    = primarySorting.Value;
            var primarySortingProperty = primarySorting.Key;

            var sortedQuery = primarySortingOrder == SortOrder.Descending
                ? query.OrderByDescending(primarySortingProperty)
                : query.OrderBy(primarySortingProperty);

            for (var i = 1; i < sorting.Count; i++)
            {
                var sort         = sorting.ElementAt(i);
                var sortOrder    = sort.Value;
                var sortProperty = sort.Key;

                sortedQuery = sortOrder == SortOrder.Descending
                    ? sortedQuery.ThenByDescending(sortProperty)
                    : sortedQuery.ThenBy(sortProperty);
            }

            return(sortedQuery);
        }
Exemple #30
0
        public static IQueryable <T> ApplyFetchingOptions <T>(this IQueryable <T> query, IRepositoryConventions conventions, IQueryOptions <T> options) where T : class
        {
            Guard.NotNull(query, nameof(query));

            var fetchingPaths = options.DefaultIfFetchStrategyEmpty(conventions).PropertyPaths.ToList();

            if (fetchingPaths.Any())
            {
                query = fetchingPaths.Aggregate(query, (current, path) => current.Include(path));
            }

            return(query);
        }