Beispiel #1
0
        /// <summary>
        /// Returns sequence, containing entities (described by their <paramref name="info"/>)
        /// from first result set of data reader, that satisfies to passed filtering <paramref name="criteria"/>.
        /// </summary>
        /// <exception cref="DbException">The connection-level error that occurred while opening the connection. </exception>
        protected virtual IEnumerable <object> GetMainEntities(IAdoEntityInfo info, ICollection <IDataCriterion> criteria)
        {
            var parameters = criteria.Select(x => ParameterWith(info, x));
            var connection = GetConnection();
            var behavior   = GetBehaviorFor(info);

            try {
                using (var command = CommandFor(ReadCommandText(info, criteria), new DbActionArgs(connection), parameters)) {
                    connection.Open();
                    using (var reader = command.ExecuteReader(behavior)) {
                        info.InitReaderColumns(reader);

                        while (reader.Read())
                        {
                            object keyId;
                            yield return(ReadItem(reader, info, null, out keyId));
                        }
                    }
                }
            }
            finally {
                connection.Close();
                connection.Dispose();
            }
        }
Beispiel #2
0
        /// <summary>
        /// Returns values of one property/column of entities, that satisfying passed filtering <paramref name="criteria"/>.
        /// </summary>
        /// <exception cref="DbException">The connection-level error that occurred while opening the connection. </exception>
        protected virtual IEnumerable <object> ReadColumn(string columnName, IAdoEntityInfo info, ICollection <IDataCriterion> criteria)
        {
            var parameters = criteria.Select(x => ParameterWith(info, x));

            var idx = info.ReaderColumns != null?info.IndexOf(columnName) : -1;

            var behavior   = GetBehaviorFor(info);
            var connection = GetConnection();

            try {
                using (var command = CommandFor(ReadCommandText(info, criteria), new DbActionArgs(connection), parameters)) {
                    connection.Open();
                    using (var reader = command.ExecuteReader(behavior)) {
                        if (idx < 0)
                        {
                            info.InitReaderColumns(reader);
                            idx = info.IndexOf(columnName);
                        }

                        while (reader.Read())
                        {
                            yield return(reader.GetValue(idx));
                        }
                    }
                }
            }
            finally {
                connection.Close();
                connection.Dispose();
            }
        }
Beispiel #3
0
        public Includeon(IncludeChildrenAttribute inclusion, IAdoEntityInfo ownerInfo, Func <Type, IAdoEntityInfo> getInfoCallback)
        {
            Attribute        = inclusion;
            _ownerInfo       = ownerInfo;
            _getInfoCallback = getInfoCallback;

            var propertyPath = ownerInfo.EntityType.GetPropertyPath(inclusion.TargetPath);

            if (propertyPath == null)
            {
                throw new InvalidOperationException($"Can't find property with TargetPath '{inclusion.TargetPath}', specified in {nameof(IncludeChildrenAttribute)} on type {ownerInfo.EntityType}");
            }

            _targetProperty = propertyPath.GetTargetProperty();
        }
Beispiel #4
0
        string GetForeignKeyName(IAdoEntityInfo mainInfo, IAdoEntityInfo foreignInfo, Func <PropertyInfo, bool> subCriteria = null, string navigationPropName = null)
        {
            if (mainInfo.ForeignKeys.Any())
            {
                var fk = mainInfo.ForeignKeys.Values.FirstOrDefault(x => x.Relationship == Relationship.ManyToOne && x.ForeignEntityName == foreignInfo.EntityName);
                if (fk != null)
                {
                    return(fk.Name);
                }
            }

            subCriteria = subCriteria ?? (info => true);

            var ownerProps            = mainInfo.EntityType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();
            var foreignNavigationProp = ownerProps.Where(x => x.PropertyType.IsAssignableFrom(foreignInfo.EntityType) && subCriteria(x)).ToArray();

            if (foreignNavigationProp.Length > 1)
            {
                Log.TraceEvent(TraceEventType.Warning,
                               $"{nameof(GetForeignKeyFromMainEntityToCurrent)}: Founded more than one possible navigation keys for includeon '{foreignInfo.EntityName}'." +
                               "Chosen foreign key can be wrong.");
            }
            else if (foreignNavigationProp.Length == 1)
            {
                var possibleName = foreignNavigationProp.Single().Name + "Id";
                if (ownerProps.Any(x => x.Name == possibleName))
                {
                    return(possibleName);
                }
            }


            var anotherPossibleName = navigationPropName ?? foreignInfo.EntityType.Name + "Id";

            if (ownerProps.Any(x => x.Name == anotherPossibleName))
            {
                return(anotherPossibleName);
            }

            return(null);
        }
Beispiel #5
0
        /// <summary>
        /// Returns one single entity, by reading it's data from <paramref name="reader"/>.
        /// It uses <paramref name="includeon"/> if it was specified, otherwise - it uses <paramref name="mainEntityInfo"/>.
        /// It also return identifier of entity in <paramref name="keyId"/> outer parameter.
        /// </summary>
        /// <param name="reader">Reader contained entities data.</param>
        /// <param name="mainEntityInfo">Info about entity. Used if <paramref name="includeon"/> is not specified (equals to null).</param>
        /// <param name="includeon">Info about includeon. Can be unspecified. See <see cref="IncludeChildrenAttribute"/> for more details.</param>
        /// <param name="keyId">
        /// Identifier of returned entity.
        /// If <paramref name="includeon"/> parameter unspecified, or represents single field includeon - <paramref name="keyId"/> will contain primary key of returned entity.
        /// If <paramref name="includeon"/> specified and represents sum-collection of main entity (<see cref="IIncludeon.IsCollection"/>)
        ///     - <paramref name="keyId"/> will contain key primary key of main entity (not the key of returned one).
        /// </param>
        /// <returns>Main entity (when <paramref name="includeon"/> unspecified) or entity described by <paramref name="includeon"/>.</returns>
        protected virtual object ReadItem(DbDataReader reader, IAdoEntityInfo mainEntityInfo, [CanBeNull] Includeon includeon, out object keyId)
        {
            var entityType = includeon?.Info.EntityType ?? mainEntityInfo.EntityType;

            var item = Activator.CreateInstance(entityType);

            keyId = null;

            var isKey = includeon == null
                ? IsPrimaryKey
                : includeon.IsCollection
                    ? (Func <string, IAdoEntityInfo, Includeon, bool>)IsKeyOfMainEntityInForeign
                    : IsPrimaryKey;


            var columns = includeon?.Info.ReaderColumns ?? mainEntityInfo.ReaderColumns;

            for (var i = 0; i < columns.Length; i++)
            {
                var name  = columns[i];
                var value = reader.GetValue(i);
                if (value == null || value.GetType().FullName == "System.DBNull")
                {
                    continue;
                }

                if (isKey(name, mainEntityInfo, includeon))
                {
                    keyId = value;
                }

                if (!item.TrySet(name, value))
                {
                    Log.TraceEvent(TraceEventType.Warning, $"Can't set property {name} from '{entityType.FullName}' context.");
                }
            }
            return(item);
        }
Beispiel #6
0
 protected override TimeSpan CacheTimeoutOf(IAdoEntityInfo info)
 {
     return(TimeSpan.MaxValue);
 }
Beispiel #7
0
 /// <summary>
 /// Checks, is property represend foreign key to main entity from the included.
 /// </summary>
 protected virtual bool IsKeyOfMainEntityInForeign([NotNull] string propertyName, [NotNull] IAdoEntityInfo mainEntityInfo, [NotNull] Includeon includeon)
 {
     return(propertyName == includeon.ForeignKeyFromCurrentEntityToMain);
 }
Beispiel #8
0
 /// <summary>
 /// Checks, is property of entity represents it's primary key.
 /// </summary>
 protected abstract bool IsPrimaryKey([NotNull] string propertyName, [NotNull] IAdoEntityInfo mainEntityInfo, [CanBeNull] Includeon includeon);
Beispiel #9
0
        /// <summary>
        /// Returns sequence of entities, that satisfies to passed filtering <paramref name="criteria"/>,
        /// including additional result sets, of data reader.
        /// See <see cref="IncludeChildrenAttribute"/> and <see cref="IIncludeon"/> for more details.
        /// </summary>
        /// <exception cref="DbException">The connection-level error that occurred while opening the connection. </exception>
        /// <seealso cref="IncludeChildrenAttribute"/>
        /// <seealso cref="IIncludeon"/>
        protected virtual IEnumerable <object> ReadToEnd(IAdoEntityInfo mainObjectInfo, ICollection <IDataCriterion> criteria)
        {
            var parameters = criteria.Select(x => ParameterWith(mainObjectInfo, x));
            var connection = GetConnection();

            var behavior = GetBehaviorFor(mainObjectInfo);

            try {
                using (var command = CommandFor(ReadCommandText(mainObjectInfo, criteria), new DbActionArgs(connection), parameters)) {
                    connection.Open();
                    using (var reader = command.ExecuteReader(behavior)) {
                        mainObjectInfo.InitReaderColumns(reader);

                        var hasIncludeons = mainObjectInfo.Inclusions.Any();

                        var mainObjects = hasIncludeons ? new Dictionary <object, object>() : null;

                        while (reader.Read())
                        {
                            object keyId;
                            var    item = ReadItem(reader, mainObjectInfo, null, out keyId);
                            if (!hasIncludeons)
                            {
                                yield return(item);
                            }

                            try {
                                mainObjects.Add(keyId, item);
                            }
                            catch (Exception e) {
                                Log.TraceEvent(TraceEventType.Critical,
                                               $"On reading '{mainObjectInfo.EntityType}' using special name {mainObjectInfo.EntityName} getted exception, " +
                                               "possibly because reader contains more then one object with same identifier.\n" +
                                               $"Identifier: {keyId}\n" +
                                               $"Exception: {e}");

                                throw;
                            }
                        }


                        var tableIndex = 0;

                        while (reader.NextResult())
                        {
                            tableIndex++;

                            Includeon includeon;
                            if (!mainObjectInfo.Inclusions.TryGetValue(tableIndex, out includeon))
                            {
                                Log.TraceEvent(TraceEventType.Warning,
                                               $"Reader for object {mainObjectInfo.EntityType.FullName} returned more than one table, " +
                                               $"but it has not includeon information for table#{tableIndex}.");
                                continue;
                            }

                            var info = includeon.Info;

                            info.InitReaderColumns(reader);


                            if (!includeon.IsCollection)
                            {
                                while (reader.Read())
                                {
                                    object keyId;
                                    var    item = ReadItem(reader, mainObjectInfo, includeon, out keyId);

                                    if (keyId == null)
                                    {
                                        Log.TraceEvent(TraceEventType.Error, $"Can't get key id from item with info {info.EntityType}, {includeon.Attribute.TargetPath} (used on entity {mainObjectInfo.EntityType}");
                                        break;
                                    }

                                    var index = tableIndex;
                                    Parallel.ForEach(mainObjects.Values,
                                                     mainObject => {
                                        object value;
                                        if (!mainObject.TryGet(includeon.ForeignKeyFromMainEntityToCurrent, out value) || !keyId.Equals(value)) // target path should be ServiceWorkplaceId, but it ServiceWorkPlace
                                        {
                                            return;                                                                                             //keyId should be just primary key of ServiceWorkPlace
                                        }
                                        if (!mainObject.TrySet(includeon.Attribute.TargetPath, item))
                                        {
                                            Log.TraceEvent(TraceEventType.Warning,
                                                           $"Can't set property {includeon.Attribute.TargetPath} from '{mainObjectInfo.EntityType.FullName}' context.\nTarget path specified for child item {info.EntityType} in result set #{index}.");
                                        }
                                    });
                                }
                            }
                            else
                            {
                                var children = new Dictionary <object, IList>(); //? Key is Main Object Primary Key, Value is children collection of main object's navigation property

                                while (reader.Read())
                                {
                                    object keyId;
                                    var    item = ReadItem(reader, mainObjectInfo, includeon, out keyId);

                                    if (keyId == null)
                                    {
                                        Log.TraceEvent(TraceEventType.Error, $"Can't get key id from item with info {info.EntityType}, {includeon.Attribute.TargetPath} (used on entity {mainObjectInfo.EntityType}");
                                        break;
                                    }


                                    IList collection;
                                    if (!children.TryGetValue(keyId, out collection))
                                    {
                                        collection = (IList)Activator.CreateInstance(includeon.TargetCollectionType);
                                        children.Add(keyId, collection);
                                    }

                                    collection.Add(item);
                                }


                                var index = tableIndex;
                                Parallel.ForEach(children,
                                                 child => {
                                    object mainObject;
                                    if (!mainObjects.TryGetValue(child.Key, out mainObject))
                                    {
                                        Log.TraceEvent(TraceEventType.Warning,
                                                       $"In result set #{index} finded data row of type {info.EntityType}, that doesn't has owner object in result set #1.\nOwner Id is {child.Key}.\nTarget path is '{includeon.Attribute.TargetPath}'.");
                                        return;
                                    }

                                    if (!mainObject.TrySet(includeon.Attribute.TargetPath, child.Value))
                                    {
                                        Log.TraceEvent(TraceEventType.Warning,
                                                       $"Can't set property {includeon.Attribute.TargetPath} from '{mainObjectInfo.EntityType.FullName}' context.\nTarget path specified for child item {info.EntityType} in result set #{index}.");
                                    }

                                    if (string.IsNullOrWhiteSpace(includeon.OwnerNavigationReferenceName))
                                    {
                                        return;
                                    }

                                    foreach (var item in child.Value)
                                    {
                                        if (!item.TrySet(includeon.OwnerNavigationReferenceName, mainObject))
                                        {
                                            Log.TraceEvent(TraceEventType.Warning,
                                                           $"Can't set property {includeon.OwnerNavigationReferenceName} from '{info.EntityType}' context. This should be reference to owner object ({mainObject})");
                                        }
                                    }
                                });
                            }
                        }


                        foreach (var item in mainObjects.Values)
                        {
                            yield return(item);
                        }
                    }
                }
            }
            finally {
                connection.Close();
                connection.Dispose();
            }
        }
Beispiel #10
0
 /// <summary>
 /// Returns entities from database, filtered with <paramref name="criteria"/>.
 /// </summary>
 /// <param name="info">Information about entity</param>
 /// <param name="criteria">Filtering criteria</param>
 protected virtual IEnumerable <object> Read(IAdoEntityInfo info, ICollection <IDataCriterion> criteria)
 {
     return(info.Inclusions?.Any() == true
         ? ReadToEnd(info, criteria)
         : GetMainEntities(info, criteria));
 }
Beispiel #11
0
 protected virtual TimeSpan CacheTimeoutOf(IAdoEntityInfo info)
 {
     return(info.CacheTimeout);
 }