Beispiel #1
0
        private static object GetManyToOneChild <T>(this SQLiteConnection conn, T element,
                                                    PropertyInfo relationshipProperty,
                                                    bool recursive, ObjectCache objectCache)
        {
            var          type = element.GetType();
            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            Assert(enclosedType == EnclosedType.None, type, relationshipProperty, "ManyToOne relationship cannot be of type List or Array");

            var otherEntityPrimaryKeyProperty = entityType.GetPrimaryKey();

            Assert(otherEntityPrimaryKeyProperty != null, type, relationshipProperty,
                   "ManyToOne relationship destination must have Primary Key");

            var currentEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty);

            Assert(currentEntityForeignKeyProperty != null, type, relationshipProperty, "ManyToOne relationship origin must have Foreign Key");

            var tableMapping = conn.GetMapping(entityType);

            Assert(tableMapping != null, type, relationshipProperty, "There's no mapping table for OneToMany relationship destination");

            object value             = null;
            var    isLoadedFromCache = false;
            var    foreignKeyValue   = currentEntityForeignKeyProperty.GetValue(element, null);

            if (foreignKeyValue != null)
            {
                // Try to load from cache when possible
                if (recursive)
                {
                    value = GetObjectFromCache(entityType, foreignKeyValue, objectCache);
                }
                if (value == null)
                {
                    value = conn.Find(foreignKeyValue, tableMapping);
                }
                else
                {
                    isLoadedFromCache = true;
                }
            }

            relationshipProperty.SetValue(element, value, null);

            if (value != null && !isLoadedFromCache && recursive)
            {
                SaveObjectToCache(value, otherEntityPrimaryKeyProperty.GetValue(value, null), objectCache);
                conn.GetChildrenRecursive(value, true, recursive, objectCache);
            }

            return(value);
        }
Beispiel #2
0
        private static IEnumerable GetManyToManyChildren <T>(this SQLiteConnection conn, T element,
                                                             PropertyInfo relationshipProperty,
                                                             bool recursive, ObjectCache objectCache)
        {
            var          type = element.GetType();
            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            var currentEntityPrimaryKeyProperty = type.GetPrimaryKey();
            var otherEntityPrimaryKeyProperty   = entityType.GetPrimaryKey();
            var manyToManyMetaInfo = type.GetManyToManyMetaInfo(relationshipProperty);
            var currentEntityForeignKeyProperty = manyToManyMetaInfo.OriginProperty;
            var otherEntityForeignKeyProperty   = manyToManyMetaInfo.DestinationProperty;
            var intermediateType = manyToManyMetaInfo.IntermediateType;
            var tableMapping     = conn.GetMapping(entityType);

            Assert(enclosedType != EnclosedType.None, type, relationshipProperty, "ManyToMany relationship must be a List or Array");
            Assert(currentEntityPrimaryKeyProperty != null, type, relationshipProperty, "ManyToMany relationship origin must have Primary Key");
            Assert(otherEntityPrimaryKeyProperty != null, type, relationshipProperty, "ManyToMany relationship destination must have Primary Key");
            Assert(intermediateType != null, type, relationshipProperty, "ManyToMany relationship intermediate type cannot be null");
            Assert(currentEntityForeignKeyProperty != null, type, relationshipProperty, "ManyToMany relationship origin must have a foreign key defined in the intermediate type");
            Assert(otherEntityForeignKeyProperty != null, type, relationshipProperty, "ManyToMany relationship destination must have a foreign key defined in the intermediate type");
            Assert(tableMapping != null, type, relationshipProperty, "There's no mapping table defined for ManyToMany relationship origin");

            IList cascadeElements = new List <object>();
            IList values          = null;
            var   primaryKeyValue = currentEntityPrimaryKeyProperty.GetValue(element, null);

            if (primaryKeyValue != null)
            {
                // Obtain the relationship keys
                var keysQuery = string.Format("select {0} from {1} where {2} = ?", otherEntityForeignKeyProperty.GetColumnName(),
                                              intermediateType.GetTableName(), currentEntityForeignKeyProperty.GetColumnName());

                var query = string.Format("select * from {0} where {1} in ({2})", entityType.GetTableName(),
                                          otherEntityPrimaryKeyProperty.GetColumnName(), keysQuery);

                var queryResults = conn.Query(tableMapping, query, primaryKeyValue);

                Array array = null;

                // Create a generic list of the expected type
                if (enclosedType == EnclosedType.List)
                {
                    values = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(entityType));
                }
                else
                {
                    values = array = Array.CreateInstance(entityType, queryResults.Count);
                }

                int i = 0;
                foreach (var result in queryResults)
                {
                    // Replace obtained value with a cached one whenever possible
                    bool loadedFromCache = false;
                    var  value           = recursive ? ReplaceWithCacheObjectIfPossible(result, otherEntityPrimaryKeyProperty, objectCache, out loadedFromCache) : result;

                    if (array != null)
                    {
                        array.SetValue(value, i);
                    }
                    else
                    {
                        values.Add(value);
                    }

                    if (!loadedFromCache)
                    {
                        cascadeElements.Add(result);
                    }

                    i++;
                }
            }

            relationshipProperty.SetValue(element, values, null);

            if (recursive)
            {
                foreach (var child in cascadeElements)
                {
                    conn.GetChildrenRecursive(child, true, recursive, objectCache);
                }
            }

            return(values);
        }
Beispiel #3
0
        private static IEnumerable GetOneToManyChildren <T>(this SQLiteConnection conn, T element,
                                                            PropertyInfo relationshipProperty,
                                                            bool recursive, ObjectCache objectCache)
        {
            var          type = element.GetType();
            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            Assert(enclosedType != EnclosedType.None, type, relationshipProperty, "OneToMany relationship must be a List or Array");

            var currentEntityPrimaryKeyProperty = type.GetPrimaryKey();

            Assert(currentEntityPrimaryKeyProperty != null, type, relationshipProperty, "OneToMany relationship origin must have Primary Key");

            var otherEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true);

            Assert(otherEntityForeignKeyProperty != null, type, relationshipProperty,
                   "OneToMany relationship destination must have Foreign Key to the origin class");

            var otherEntityPrimaryKeyProperty = entityType.GetPrimaryKey();

            var tableMapping = conn.GetMapping(entityType);

            Assert(tableMapping != null, type, relationshipProperty, "There's no mapping table for OneToMany relationship destination");

            var inverseProperty = type.GetInverseProperty(relationshipProperty);

            IList cascadeElements = new List <object>();
            IList values          = null;
            var   primaryKeyValue = currentEntityPrimaryKeyProperty.GetValue(element, null);

            if (primaryKeyValue != null)
            {
                var query = string.Format("select * from {0} where {1} = ?", entityType.GetTableName(),
                                          otherEntityForeignKeyProperty.GetColumnName());
                var queryResults = conn.Query(tableMapping, query, primaryKeyValue);

                Array array = null;

                // Create a generic list of the expected type
                if (enclosedType == EnclosedType.List)
                {
                    values = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(entityType));
                }
                else
                {
                    values = array = Array.CreateInstance(entityType, queryResults.Count);
                }

                int i = 0;
                foreach (var result in queryResults)
                {
                    // Replace obtained value with a cached one whenever possible
                    bool loadedFromCache = false;
                    var  value           = recursive ? ReplaceWithCacheObjectIfPossible(result, otherEntityPrimaryKeyProperty, objectCache, out loadedFromCache) : result;

                    if (array != null)
                    {
                        array.SetValue(value, i);
                    }
                    else
                    {
                        values.Add(value);
                    }

                    if (!loadedFromCache)
                    {
                        cascadeElements.Add(result);
                    }

                    i++;
                }
            }

            relationshipProperty.SetValue(element, values, null);

            if (inverseProperty != null && values != null)
            {
                // Stablish inverse relationships (we already have that object anyway)
                foreach (var value in values)
                {
                    inverseProperty.SetValue(value, element, null);
                }
            }

            if (recursive)
            {
                foreach (var child in cascadeElements)
                {
                    conn.GetChildrenRecursive(child, true, recursive, objectCache);
                }
            }

            return(values);
        }
Beispiel #4
0
        private static object GetOneToOneChild <T>(this SQLiteConnection conn, T element,
                                                   PropertyInfo relationshipProperty,
                                                   bool recursive, ObjectCache objectCache)
        {
            var          type = element.GetType();
            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            Assert(enclosedType == EnclosedType.None, type, relationshipProperty, "OneToOne relationship cannot be of type List or Array");

            var currentEntityPrimaryKeyProperty = type.GetPrimaryKey();
            var otherEntityPrimaryKeyProperty   = entityType.GetPrimaryKey();

            Assert(currentEntityPrimaryKeyProperty != null || otherEntityPrimaryKeyProperty != null, type, relationshipProperty,
                   "At least one entity in a OneToOne relationship must have Primary Key");

            var currentEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty);
            var otherEntityForeignKeyProperty   = type.GetForeignKeyProperty(relationshipProperty, inverse: true);

            Assert(currentEntityForeignKeyProperty != null || otherEntityForeignKeyProperty != null, type, relationshipProperty,
                   "At least one entity in a OneToOne relationship must have Foreign Key");

            var hasForeignKey        = otherEntityPrimaryKeyProperty != null && currentEntityForeignKeyProperty != null;
            var hasInverseForeignKey = currentEntityPrimaryKeyProperty != null && otherEntityForeignKeyProperty != null;

            Assert(hasForeignKey || hasInverseForeignKey, type, relationshipProperty,
                   "Missing either ForeignKey or PrimaryKey for a complete OneToOne relationship");

            var tableMapping = conn.GetMapping(entityType);

            Assert(tableMapping != null, type, relationshipProperty, "There's no mapping table for OneToOne relationship");

            var inverseProperty = type.GetInverseProperty(relationshipProperty);

            object value             = null;
            var    isLoadedFromCache = false;

            if (hasForeignKey)
            {
                var foreignKeyValue = currentEntityForeignKeyProperty.GetValue(element, null);
                if (foreignKeyValue != null)
                {
                    // Try to load from cache when possible
                    if (recursive)
                    {
                        value = GetObjectFromCache(entityType, foreignKeyValue, objectCache);
                    }
                    if (value == null)
                    {
                        value = conn.Find(foreignKeyValue, tableMapping);
                    }
                    else
                    {
                        isLoadedFromCache = true;
                    }
                }
            }
            else
            {
                var primaryKeyValue = currentEntityPrimaryKeyProperty.GetValue(element, null);
                if (primaryKeyValue != null)
                {
                    var query = string.Format("select * from {0} where {1} = ? limit 1", entityType.GetTableName(),
                                              otherEntityForeignKeyProperty.GetColumnName());
                    value = conn.Query(tableMapping, query, primaryKeyValue).FirstOrDefault();
                    // Its a OneToOne, take only the first
                }

                // Try to replace the loaded entity with the same object from the cache whenever possible
                value = recursive ? ReplaceWithCacheObjectIfPossible(value, otherEntityPrimaryKeyProperty, objectCache, out isLoadedFromCache) : value;
            }

            relationshipProperty.SetValue(element, value, null);

            if (value != null && inverseProperty != null)
            {
                inverseProperty.SetValue(value, element, null);
            }

            if (value != null && !isLoadedFromCache && recursive)
            {
                SaveObjectToCache(value, otherEntityPrimaryKeyProperty.GetValue(value, null), objectCache);
                conn.GetChildrenRecursive(value, true, recursive, objectCache);
            }

            return(value);
        }