Beispiel #1
0
        internal static void PopulateChildEntity(ref string propertyName, ref object value, ORMEntity childEntity)
        {
            propertyName = propertyName.Split('_').Last();

            var childPropertyType = childEntity.GetPropertyInfo(propertyName).PropertyType;

            // Unit tests columns are all of type string, therefore they require to be converted to their respective type.
            if (Nullable.GetUnderlyingType(childPropertyType) != null && value != DBNull.Value)
            {
                value = Convert.ChangeType(value, Nullable.GetUnderlyingType(childPropertyType));
            }
            else if (!childPropertyType.IsSubclassOf(typeof(ORMEntity)) && value != DBNull.Value)
            {
                value = Convert.ChangeType(value, childPropertyType);
            }
        }
Beispiel #2
0
        internal static void SetEntityProperty(ORMEntity entity, IDataReader reader, SQLBuilder sqlBuilder, int iteration, bool isEntityManyTomany = false)
        {
            // All joins (child-entities) are filled through PopulateChildEntity, therefore we can
            // skip anything past the current entity (parent) within the reader.
            if (iteration >= sqlBuilder.TableNameColumnCount.First().Value&& !isEntityManyTomany)
            {
                // Skipping.
                return;
            }

            var propertyName = reader.GetName(iteration);

            if (UnitTestUtilities.IsUnitTesting)
            {
                propertyName = propertyName.Split('_').Last();
            }

            var entityPropertyInfo = entity.GetPropertyInfo(propertyName);

            if (null == entityPropertyInfo)
            {
                if (propertyName == entity.GetType().Name)
                {
                    throw new ORMIllegalColumnNameException($"The column [{propertyName}] has not been implemented in entity [{entity.GetType().Name}], but can't have the same name as its enclosing type.");
                }

                throw new NotImplementedException($"The column [{propertyName}] has not been implemented in entity [{entity.GetType().Name}].");
            }
            else if (!entityPropertyInfo.CanWrite)
            {
                throw new ReadOnlyException($"Property [{propertyName}] is read-only in [{entity.GetType().Name}].");
            }

            object value = null;

            switch (entityPropertyInfo.PropertyType)
            {
            case Type type when type == typeof(DateTime?):
                value = reader.GetValue(iteration);
                break;

            case Type type when type == typeof(DateTime):
                if (reader.GetValue(iteration) == DBNull.Value)
                {
                    throw new ORMPropertyNotNullableException($"Property [{propertyName}] is not nullable, but the database column equivelant is.");
                }

                value = reader.GetValue(iteration);
                break;

            case Type type when type.IsSubclassOf(typeof(ORMEntity)):
                if (reader.GetValue(iteration) == DBNull.Value)
                {
                    break;
                }

                // If there are no joins provided or none matched the current type we don't want
                // to fetch the child-object.
                if (sqlBuilder.Joins.Count == 0 || !sqlBuilder.Joins.Any(x => x.LeftPropertyInfo.PropertyType == type))
                {
                    value = null;
                    break;
                }

                foreach (var join in sqlBuilder.Joins)
                {
                    if (join.LeftPropertyInfo.PropertyType == type)
                    {
                        var subEntity = Activator.CreateInstance(type.UnderlyingSystemType) as ORMEntity;

                        PopulateChildEntity(entity, subEntity, reader, sqlBuilder);

                        value = subEntity;

                        entity.Relations.Add(value as ORMEntity);

                        if (entityPropertyInfo == null)
                        {
                            entityPropertyInfo = entity.GetType().GetProperty("Organisation", entity.PublicIgnoreCaseFlags);
                        }

                        break;
                    }
                }

                break;

            default:
                value = reader.GetValue(iteration);
                break;
            }

            if (UnitTestUtilities.IsUnitTesting)
            {
                // Unit tests columns are all of type string, therefore they require to be converted to their respective type.
                if (Nullable.GetUnderlyingType(entityPropertyInfo.PropertyType) != null && value != DBNull.Value)
                {
                    value = Convert.ChangeType(value, Nullable.GetUnderlyingType(entityPropertyInfo.PropertyType));
                }
                else if (!entityPropertyInfo.PropertyType.IsSubclassOf(typeof(ORMEntity)) && value != DBNull.Value)
                {
                    value = Convert.ChangeType(value, entityPropertyInfo.PropertyType);
                }
            }

            if (reader.GetValue(iteration) == DBNull.Value)
            {
                entityPropertyInfo.SetValue(entity, null);
            }
            else
            {
                entityPropertyInfo.SetValue(entity, value);
            }
        }
Beispiel #3
0
        private static IDataReader ApplyEntityJoinsToReader(ORMEntity entity, IDataReader reader, SQLBuilder sqlBuilder)
        {
            foreach (var join in sqlBuilder.Joins)
            {
                if (join.IsManyToMany)
                {
                    if (join.LeftPropertyInfo.ReflectedType == entity.GetType())
                    {
                        foreach (var property in entity.GetType().GetProperties())
                        {
                            if (property.PropertyType == join.RightTableAttribute.CollectionTypeRight &&
                                property.CustomAttributes.Any(x => x.AttributeType == typeof(ORMManyToMany)))
                            {
                                var parentDataTable = new DataTable();
                                parentDataTable.Load(reader);

                                var childTableName  = join.RightTableAttribute.EntityType.Name;
                                var childEntity     = Activator.CreateInstance(join.RightTableAttribute.EntityType, true) as ORMEntity;
                                var childCollection = Activator.CreateInstance(join.RightTableAttribute.CollectionType) as IEnumerable <ORMEntity>;

                                foreach (var childProperty in childEntity.GetType().GetProperties(childEntity.PublicFlags))
                                {
                                    var executedQuery = (string)childCollection.GetType().GetProperty(nameof(ORMCollection <ORMEntity> .ExecutedQuery)).GetValue(childCollection);

                                    if (!string.IsNullOrEmpty(executedQuery))
                                    {
                                        break;
                                    }

#pragma warning disable IDE0019 // Use pattern matching
                                    var fkAttribute = childProperty.GetCustomAttributes(typeof(ORMForeignKeyAttribute), false).FirstOrDefault() as ORMForeignKeyAttribute;
#pragma warning restore IDE0019 // Use pattern matching

                                    if (fkAttribute != null && fkAttribute.Relation == entity.GetType())
                                    {
                                        BinaryExpression whereExpression = null;

                                        for (int i = 0; i < childEntity.PrimaryKey.Count; i++)
                                        {
                                            if (!childEntity.IsForeignKeyOfType(childEntity.PrimaryKey.Keys[i].PropertyName, entity.GetType()))
                                            {
                                                continue;
                                            }

                                            // Contains the id represented as a MemberExpression: {x.InternalPropertyName}.
                                            var memberExpression = Expression.Property(Expression.Parameter(childEntity.GetType(), $"x"), childEntity.GetPrimaryKeyPropertyInfo()[i]);

                                            // Contains the actual id represented as a ConstantExpression: {id_value}.
                                            var constantExpression = Expression.Constant(entity.PrimaryKey.Keys[i].Value, entity.PrimaryKey.Keys[i].Value.GetType());

                                            // Combines the expressions represtend as a Expression: {(x.InternalPropertyName == id_value)}
                                            if (whereExpression == null)
                                            {
                                                whereExpression = Expression.Equal(memberExpression, constantExpression);
                                            }
                                        }

                                        // Sets the InternalWhere with the WhereExpression.
                                        childCollection.GetType().GetMethod(nameof(ORMCollection <ORMEntity> .InternalWhere), entity.NonPublicFlags, null, new Type[] { typeof(BinaryExpression) }, null).Invoke(childCollection, new object[] { whereExpression });

                                        // Fetches the data.
                                        childCollection.GetType().GetMethod(nameof(ORMCollection <ORMEntity> .Fetch), childEntity.NonPublicFlags, null, new Type[] { typeof(ORMEntity), typeof(long), typeof(Expression) }, null).Invoke(childCollection, new object[] { null, -1, null });
                                    }
                                }

                                var childCollectionRight = Activator.CreateInstance(join.RightTableAttribute.CollectionTypeRight) as IEnumerable <ORMEntity>;
                                var childEntityRight     = Activator.CreateInstance(ORMUtilities.CollectionEntityRelations[childCollectionRight.GetType()]) as ORMEntity;

                                BinaryExpression whereExpressionRight = null;

                                foreach (var childEntityLeft in childCollection)
                                {
                                    for (int i = 0; i < childEntityLeft.PrimaryKey.Count; i++)
                                    {
                                        if (!childEntity.IsForeignKeyOfType(childEntityLeft.PrimaryKey.Keys[i].PropertyName, childEntityRight.GetType()))
                                        {
                                            continue;
                                        }

                                        // Contains the id represented as a MemberExpression: {x.InternalPropertyName}.
                                        var memberExpressionRight = Expression.Property(Expression.Parameter(childEntityRight.GetType(), $"x"), childEntityRight.GetPrimaryKeyPropertyInfo()[0]);

                                        // Contains the actual id represented as a ConstantExpression: {id_value}.
                                        var constantExpressionRight = Expression.Constant(childEntityLeft.PrimaryKey.Keys[i].Value, childEntityLeft.PrimaryKey.Keys[i].Value.GetType());

                                        // Combines the expressions represtend as a Expression: {(x.InternalPropertyName == id_value)}
                                        if (whereExpressionRight == null)
                                        {
                                            whereExpressionRight = Expression.Equal(memberExpressionRight, constantExpressionRight);
                                        }
                                        else
                                        {
                                            whereExpressionRight = Expression.Or(whereExpressionRight, Expression.Equal(memberExpressionRight, constantExpressionRight));
                                        }
                                    }
                                }

                                // We no longer need the old collection;
                                childCollection = Activator.CreateInstance(join.RightTableAttribute.CollectionTypeRight) as IEnumerable <ORMEntity>;

                                // Sets the InternalWhere with the WhereExpression.
                                childCollection.GetType().GetMethod(nameof(ORMCollection <ORMEntity> .InternalWhere), entity.NonPublicFlags, null, new Type[] { typeof(BinaryExpression) }, null).Invoke(childCollection, new object[] { whereExpressionRight });

                                // Fetches the data.
                                childCollection.GetType().GetMethod(nameof(ORMCollection <ORMEntity> .Fetch), entity.NonPublicFlags, null, new Type[] { typeof(ORMEntity), typeof(long), typeof(Expression) }, null).Invoke(childCollection, new object[] { null, -1, null });

                                // Sets the ManyToMany collection.
                                property.SetValue(entity, childCollection);

                                reader = parentDataTable.CreateDataReader();
                                break;
                            }
                        }
                    }
                }
                else
                {
                    foreach (var field in entity.TableScheme)
                    {
                        if (join.LeftPropertyInfo.PropertyType == entity.GetPropertyInfo(field).PropertyType)
                        {
                            var parentDataTable = new DataTable();
                            parentDataTable.Load(reader);

                            var childTableName = ORMUtilities.CollectionEntityRelations[join.LeftPropertyInfo.PropertyType].Name;
                            var childEntity    = Activator.CreateInstance(join.LeftPropertyInfo.PropertyType);
                            var childId        = parentDataTable.Rows[0][entity.TableScheme.IndexOf(field)];

                            var childReader = ORMUtilities.MemoryEntityDatabase.FetchEntityById(childTableName, entity.PrimaryKey.Keys[0], childId);

                            var childDataTable = new DataTable();
                            childDataTable.Load(childReader);

                            foreach (DataColumn column in childDataTable.Columns)
                            {
                                if (parentDataTable.Columns.Contains(column.ColumnName))
                                {
                                    childDataTable.Columns[column.ColumnName].ColumnName = $"{ childDataTable.TableName }_{ column.ColumnName }";
                                }
                            }

                            parentDataTable.Merge(childDataTable);

                            var left  = parentDataTable.Rows[0];
                            var right = parentDataTable.Rows[1];

                            foreach (DataColumn column in left.Table.Columns)
                            {
                                if (left[column] == DBNull.Value)
                                {
                                    left[column] = right[column];
                                }
                            }

                            parentDataTable.Rows.Remove(right);

                            reader = parentDataTable.CreateDataReader();
                            break;
                        }
                    }
                }
            }

            return(reader);
        }
Beispiel #4
0
        private static void PopulateManyToManyEntity(ORMEntity entity, IDataReader reader, SQLBuilder sqlBuilder)
        {
            Dictionary <ORMPrimaryKey, Dictionary <string, List <ORMEntity> > > manyToManyData = new Dictionary <ORMPrimaryKey, Dictionary <string, List <ORMEntity> > >(new ORMPrimaryKey());

            var manyToManyJoinIndexes = new List <(string, int[])>();
            var manyToManyJoinTypes   = new Dictionary <string, Type>();

            var tableIndex = 0;

            foreach (var(name, _) in sqlBuilder.TableOrder)
            {
                var objectPath       = sqlBuilder.TableNameResolvePaths.ContainsKey(name) ? sqlBuilder.TableNameResolvePaths[name] : string.Empty;
                var tableColumnCount = sqlBuilder.TableNameColumnCount[name];

                if (objectPath.StartsWith(SQLBuilder.MANY_TO_MANY_JOIN_DATA, StringComparison.Ordinal))
                {
                    var indexes = new List <int>();
                    for (int i = 0; i < tableColumnCount; i++)
                    {
                        indexes.Add(tableIndex + i);
                    }
                    manyToManyJoinIndexes.Add((objectPath.Split('.')[1], indexes.ToArray()));
                }
                tableIndex += tableColumnCount;
            }

            void AddManyToManyObject(ORMPrimaryKey key, IDataReader reader)
            {
                Dictionary <string, List <ORMEntity> > relations;

                if (manyToManyData.ContainsKey(key))
                {
                    relations = manyToManyData[key];
                }
                else
                {
                    relations           = new Dictionary <string, List <ORMEntity> >();
                    manyToManyData[key] = relations;
                }

                foreach (var(fieldName, indexes) in manyToManyJoinIndexes)
                {
                    bool IsRowEmpty(List <(string, int[])> manyToManyJoinIndexes, IDataReader reader)
                    {
                        foreach (var(fieldName, indexes) in manyToManyJoinIndexes)
                        {
                            for (int i = 0; i < indexes.Length; i++)
                            {
                                if (reader.GetValue(indexes[i]) == DBNull.Value)
                                {
                                    if ((i + 1) == indexes.Length)
                                    {
                                        return(true);
                                    }
                                }
                                else
                                {
                                    return(false);
                                }
                            }
                        }

                        return(true);
                    }

                    if (!IsRowEmpty(manyToManyJoinIndexes, reader))
                    {
                        var instance = (ORMEntity)Activator.CreateInstance(manyToManyJoinTypes[fieldName]);
                        foreach (var index in indexes)
                        {
                            SetEntityProperty(instance, reader, sqlBuilder, index, true);
                        }

                        if (relations.ContainsKey(fieldName))
                        {
                            relations[fieldName].Add(instance);
                        }
                        else
                        {
                            relations[fieldName] = new List <ORMEntity>()
                            {
                                instance
                            };
                        }
                    }
                }
            }

            int[] primaryKeyIndexes = ORMPrimaryKey.DeterminePrimaryKeyIndexes(reader, entity);

            foreach (var(fieldName, _) in manyToManyJoinIndexes)
            {
                var type = entity.GetPropertyInfo(fieldName).PropertyType;
                if (!typeof(ORMEntity).IsAssignableFrom(type.GetType()))
                {
                    type = ORMUtilities.CollectionEntityRelations[type];
                }
                manyToManyJoinTypes.Add(fieldName, type);
            }

            ORMPrimaryKey pk = new ORMPrimaryKey(reader, primaryKeyIndexes);

            //PopulateEntity(entity, reader, sqlBuilder);
            AddManyToManyObject(pk, reader);

            foreach (var kvPair in manyToManyData)
            {
                foreach (var data in kvPair.Value)
                {
                    var property = entity.GetType().GetProperty(data.Key, entity.PublicFlags);
                    if (typeof(IORMCollection <ORMEntity>).IsAssignableFrom(property.PropertyType))
                    {
                        var propertyValue = entity.GetType().GetProperty(data.Key, entity.PublicFlags).GetValue(entity);

                        if (propertyValue == null)
                        {
                            var subcollection = Activator.CreateInstance(property.PropertyType);

                            var collectionProperty = property.PropertyType.GetProperty(nameof(ORMCollection <ORMEntity> .MutableEntityCollection), entity.NonPublicFlags);
                            var list = collectionProperty.GetValue(subcollection) as IList;
                            foreach (var item in data.Value)
                            {
                                list.Add(item);
                            }
                            property.SetValue(entity, subcollection);
                        }
                        else
                        {
                            foreach (var item in data.Value)
                            {
                                propertyValue.GetType().GetMethod("Add", entity.PublicFlags).Invoke(propertyValue, new object[] { item });
                            }
                        }
                    }
                    else
                    {
                        throw new Exception("Something went wrong trying to cast to a subcollection");
                    }
                }
            }
        }