Exemplo n.º 1
0
        /// <summary>
        /// Obtains the object from the database and fetches all the properties annotated with
        /// any subclass of <c>RelationshipAttribute</c>. If the object with the specified primary key doesn't
        /// exist in the database, an exception will be raised.
        /// </summary>
        /// <returns>The object with all the children loaded</returns>
        /// <param name="conn">SQLite Net connection object</param>
        /// <param name="pk">Primary key for the object to search in the database</param>
        /// <param name="recursive">If set to <c>true</c> all the relationships with
        /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
        /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
        public static T GetWithChildren <T>(this SQLiteConnection conn, object pk, bool recursive = false) where T : new()
        {
            var element = conn.Get <T>(pk);

            conn.GetChildren(element, recursive);
            return(element);
        }
Exemplo n.º 2
0
        private static void GetChildRecursive(this SQLiteConnection conn, object element, PropertyInfo relationshipProperty, bool recursive, ObjectCache objectCache)
        {
            var relationshipAttribute = relationshipProperty.GetAttribute <RelationshipAttribute>();

            if (relationshipAttribute is OneToOneAttribute)
            {
                conn.GetOneToOneChild(element, relationshipProperty, recursive, objectCache);
            }
            else if (relationshipAttribute is OneToManyAttribute)
            {
                conn.GetOneToManyChildren(element, relationshipProperty, recursive, objectCache);
            }
            else if (relationshipAttribute is ManyToOneAttribute)
            {
                conn.GetManyToOneChild(element, relationshipProperty, recursive, objectCache);
            }
            else if (relationshipAttribute is ManyToManyAttribute)
            {
                conn.GetManyToManyChildren(element, relationshipProperty, recursive, objectCache);
            }
            else if (relationshipAttribute is TextBlobAttribute)
            {
                TextBlobOperations.GetTextBlobChild(element, relationshipProperty);
            }
        }
Exemplo n.º 3
0
        public static void InsertWithChildren <T>(this SQLiteConnection conn, T element)
        {
            RefreshForeignKeys(ref element);

            conn.Insert(element);

            conn.UpdateInverseForeignKeys(element);
        }
Exemplo n.º 4
0
        public static void UpdateWithChildren <T>(this SQLiteConnection conn, T element)
        {
            // Update the current element
            RefreshForeignKeys(ref element);
            conn.Update(element);

            // Update inverse foreign keys
            conn.UpdateInverseForeignKeys(element);
        }
Exemplo n.º 5
0
        /// <summary>
        /// The behavior is the same that <c>GetWithChildren</c> but it returns null if the object doesn't
        /// exist in the database instead of throwing an exception
        /// Obtains the object from the database and fetch all the properties annotated with
        /// any subclass of <c>RelationshipAttribute</c>. If the object with the specified primary key doesn't
        /// exist in the database, it will return null
        /// </summary>
        /// <returns>The object with all the children loaded or null if it doesn't exist</returns>
        /// <param name="conn">SQLite Net connection object</param>
        /// <param name="pk">Primary key for the object to search in the database</param>
        /// <param name="recursive">If set to <c>true</c> all the relationships with
        /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
        /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
        public static T FindWithChildren <T>(this SQLiteConnection conn, object pk, bool recursive = false) where T : new()
        {
            var element = conn.Find <T>(pk);

            if (!EqualityComparer <T> .Default.Equals(element, default(T)))
            {
                conn.GetChildren(element, recursive);
            }
            return(element);
        }
Exemplo n.º 6
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);
        }
Exemplo n.º 7
0
        private static void GetChildrenRecursive(this SQLiteConnection conn, object element, bool onlyCascadeChildren, bool recursive, ObjectCache objectCache = null)
        {
            objectCache = objectCache ?? new ObjectCache();

            foreach (var relationshipProperty in element.GetType().GetRelationshipProperties())
            {
                var relationshipAttribute = relationshipProperty.GetAttribute <RelationshipAttribute>();
                if (!onlyCascadeChildren || relationshipAttribute.IsCascadeRead)
                {
                    conn.GetChildRecursive(element, relationshipProperty, recursive, objectCache);
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// Fetches all the entities of the specified type with the filter and fetches all the relationship
        /// properties of all the returned elements.
        /// </summary>
        /// <returns>List of all the elements of the type T that matches the filter with the children already loaded</returns>
        /// <param name="conn">SQLite Net connection object</param>
        /// <param name="filter">Filter that will be passed to the <c>Where</c> clause when fetching
        /// objects from the database. No relationship properties are allowed in this filter as they
        /// are loaded afterwards</param>
        /// <param name="recursive">If set to <c>true</c> all the relationships with
        /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
        /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
        public static List <T> GetAllWithChildren <T>(this SQLiteConnection conn, Expression <Func <T, bool> > filter = null, bool recursive = false) where T : new()
        {
            var elements = conn.Table <T>();

            if (filter != null)
            {
                elements = elements.Where(filter);
            }

            var list = elements.ToList();

            foreach (T element in list)
            {
                conn.GetChildren(element, recursive);
            }

            return(list);
        }
Exemplo n.º 9
0
 private static void UpdateInverseForeignKeys <T>(this SQLiteConnection conn, T element)
 {
     foreach (var relationshipProperty in typeof(T).GetRelationshipProperties())
     {
         var relationshipAttribute = relationshipProperty.GetAttribute <RelationshipAttribute>();
         if (relationshipAttribute is OneToManyAttribute)
         {
             conn.UpdateOneToManyInverseForeignKey(element, relationshipProperty);
         }
         else if (relationshipAttribute is OneToOneAttribute)
         {
             conn.UpdateOneToOneInverseForeignKey(element, relationshipProperty);
         }
         else if (relationshipAttribute is ManyToManyAttribute)
         {
             conn.UpdateManyToManyForeignKeys(element, relationshipProperty);
         }
     }
 }
Exemplo n.º 10
0
        private static void UpdateOneToOneInverseForeignKey <T>(this SQLiteConnection conn, T element, PropertyInfo relationshipProperty)
        {
            var type = typeof(T);

            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            var originPrimaryKeyProperty  = type.GetPrimaryKey();
            var inversePrimaryKeyProperty = entityType.GetPrimaryKey();
            var inverseForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true);

            Debug.Assert(enclosedType == EnclosedType.None, "OneToOne relationships cannot be List or Array of entities");

            var inverseProperty = type.GetInverseProperty(relationshipProperty);

            if (inverseProperty != null)
            {
                EnclosedType inverseEnclosedType;
                var          inverseEntityType = inverseProperty.GetEntityType(out inverseEnclosedType);
                Debug.Assert(inverseEnclosedType == EnclosedType.None, "OneToOne inverse relationship shouldn't be List or Array");
                Debug.Assert(inverseEntityType == type, "OneToOne inverse relationship is not the expected type");
            }

            object keyValue = null;

            if (originPrimaryKeyProperty != null && inverseForeignKeyProperty != null)
            {
                keyValue = originPrimaryKeyProperty.GetValue(element, null);
            }

            object childKey = null;
            var    child    = relationshipProperty.GetValue(element, null);

            if (child != null)
            {
                if (inverseForeignKeyProperty != null && keyValue != null)
                {
                    inverseForeignKeyProperty.SetValue(child, keyValue, null);
                }
                if (inverseProperty != null)
                {
                    inverseProperty.SetValue(child, element, null);
                }
                if (inversePrimaryKeyProperty != null)
                {
                    childKey = inversePrimaryKeyProperty.GetValue(child, null);
                }
            }


            // Objects already updated, now change the database
            if (inverseForeignKeyProperty != null && inversePrimaryKeyProperty != null)
            {
                string tableName             = entityType.GetTableName();
                string inverseForeignKeyName = inverseForeignKeyProperty.GetColumnName();
                string inversePrimaryKeyName = inversePrimaryKeyProperty.GetColumnName();

                var query = String.Format("update {0} set {1} = ? where {2} == ?",
                                          tableName, inverseForeignKeyName, inversePrimaryKeyName);
                conn.Execute(query, keyValue, childKey);

                // Delete previous relationships
                var deleteQuery = String.Format("update {0} set {1} = NULL where {1} == ? and {2} not in (?)",
                                                tableName, inverseForeignKeyName, inversePrimaryKeyName);
                conn.Execute(deleteQuery, keyValue, childKey);
            }
        }
Exemplo n.º 11
0
 /// <summary>
 /// Fetches a specific property of the current object and keeps fetching recursively if the
 /// <c>recursive</c> flag has been set.
 /// </summary>
 /// <param name="conn">SQLite Net connection object</param>
 /// <param name="element">Element used to load all the relationship properties</param>
 /// <param name="relationshipProperty">Name of the property to fetch from the database</param>
 /// <param name="recursive">If set to <c>true</c> all the relationships with
 /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
 /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
 public static void GetChild <T>(this SQLiteConnection conn, T element, string relationshipProperty, bool recursive = false)
 {
     conn.GetChild(element, element.GetType().GetRuntimeProperty(relationshipProperty), recursive);
 }
Exemplo n.º 12
0
 /// <summary>
 /// Fetches a specific property of the current object and keeps fetching recursively if the
 /// <c>recursive</c> flag has been set.
 /// </summary>
 /// <param name="conn">SQLite Net connection object</param>
 /// <param name="element">Element used to load all the relationship properties</param>
 /// <param name="propertyExpression">Expression that returns the property to be loaded from the database.
 /// This variant is useful to avoid spelling mistakes and make the code refactor-safe.</param>
 /// <param name="recursive">If set to <c>true</c> all the relationships with
 /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
 /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
 public static void GetChild <T>(this SQLiteConnection conn, T element, Expression <Func <T, object> > propertyExpression, bool recursive = false)
 {
     conn.GetChild(element, ReflectionExtensions.GetProperty(propertyExpression), recursive);
 }
Exemplo n.º 13
0
 /// <summary>
 /// Fetches a specific property of the current object and keeps fetching recursively if the
 /// <c>recursive</c> flag has been set.
 /// </summary>
 /// <param name="conn">SQLite Net connection object</param>
 /// <param name="element">Element used to load all the relationship properties</param>
 /// <param name="relationshipProperty">Property to load from the database</param>
 /// <param name="recursive">If set to <c>true</c> all the relationships with
 /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
 /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
 public static void GetChild <T>(this SQLiteConnection conn, T element, PropertyInfo relationshipProperty, bool recursive = false)
 {
     conn.GetChildRecursive(element, relationshipProperty, recursive, new ObjectCache());
 }
Exemplo n.º 14
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);
        }
Exemplo n.º 15
0
 /// <summary>
 /// Fetches all the properties annotated with any subclass of <c>RelationshipAttribute</c> of the current
 /// object and keeps fetching recursively if the <c>recursive</c> flag has been set.
 /// </summary>
 /// <param name="conn">SQLite Net connection object</param>
 /// <param name="element">Element used to load all the relationship properties</param>
 /// <param name="recursive">If set to <c>true</c> all the relationships with
 /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
 /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
 public static void GetChildren <T>(this SQLiteConnection conn, T element, bool recursive = false)
 {
     GetChildrenRecursive(conn, element, false, recursive);
 }
Exemplo n.º 16
0
        private static void UpdateManyToManyForeignKeys <T>(this SQLiteConnection conn, T element, PropertyInfo relationshipProperty)
        {
            var type = typeof(T);

            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;

            Debug.Assert(enclosedType != EnclosedType.None, "ManyToMany relationship must be a List or Array");
            Debug.Assert(currentEntityPrimaryKeyProperty != null, "ManyToMany relationship origin must have Primary Key");
            Debug.Assert(otherEntityPrimaryKeyProperty != null, "ManyToMany relationship destination must have Primary Key");
            Debug.Assert(intermediateType != null, "ManyToMany relationship intermediate type cannot be null");
            Debug.Assert(currentEntityForeignKeyProperty != null, "ManyToMany relationship origin must have a foreign key defined in the intermediate type");
            Debug.Assert(otherEntityForeignKeyProperty != null, "ManyToMany relationship destination must have a foreign key defined in the intermediate type");

            var primaryKey = currentEntityPrimaryKeyProperty.GetValue(element, null);

            // Obtain the list of children keys
            var childList    = (IEnumerable)relationshipProperty.GetValue(element, null);
            var childKeyList = (from object child in childList ?? new List <object>()
                                select otherEntityPrimaryKeyProperty.GetValue(child, null)).ToList();

            var childrenKeysParams = String.Join(",", childKeyList.Select(x => "?"));

            // Check for already existing relationships
            var currentChildrenQuery = string.Format("select {0} from {1} where {2} == ? and {0} in ({3})",
                                                     otherEntityForeignKeyProperty.Name, intermediateType.Name, currentEntityForeignKeyProperty.Name, childrenKeysParams);

            var sqlParams = new List <object> {
                primaryKey
            };

            sqlParams.AddRange(childKeyList);

            var currentChildKeyList =
                from object child in conn.Query(conn.GetMapping(intermediateType), currentChildrenQuery, sqlParams.ToArray())
                select otherEntityForeignKeyProperty.GetValue(child, null);


            // Insert missing relationships in the intermediate table
            var missingChildKeyList        = childKeyList.Where(o => !currentChildKeyList.Contains(o)).ToList();
            var missingIntermediateObjects = new List <object>(missingChildKeyList.Count);

            foreach (var missingChildKey in missingChildKeyList)
            {
                var intermediateObject = Activator.CreateInstance(intermediateType);
                currentEntityForeignKeyProperty.SetValue(intermediateObject, primaryKey, null);
                otherEntityForeignKeyProperty.SetValue(intermediateObject, missingChildKey, null);

                missingIntermediateObjects.Add(intermediateObject);
            }

            conn.InsertAll(missingIntermediateObjects);

            // Delete any other pending relationship
            var deleteQuery = string.Format("delete from {0} where {1} == ? and {2} not in ({3})",
                                            intermediateType.Name, currentEntityForeignKeyProperty.Name,
                                            otherEntityForeignKeyProperty.Name, childrenKeysParams);

            conn.Execute(deleteQuery, sqlParams.ToArray());
        }
Exemplo n.º 17
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);
        }
Exemplo n.º 18
0
 public static void DeleteWithChildren <T>(this SQLiteConnection conn, T element)
 {
 }
Exemplo n.º 19
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);
        }
Exemplo n.º 20
0
        private static void UpdateOneToManyInverseForeignKey <T>(this SQLiteConnection conn, T element, PropertyInfo relationshipProperty)
        {
            var type = typeof(T);

            EnclosedType enclosedType;
            var          entityType = relationshipProperty.GetEntityType(out enclosedType);

            var originPrimaryKeyProperty  = type.GetPrimaryKey();
            var inversePrimaryKeyProperty = entityType.GetPrimaryKey();
            var inverseForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true);

            Debug.Assert(enclosedType != EnclosedType.None, "OneToMany relationships must be List or Array of entities");
            Debug.Assert(originPrimaryKeyProperty != null, "OneToMany relationships require Primary Key in the origin entity");
            Debug.Assert(inversePrimaryKeyProperty != null, "OneToMany relationships require Primary Key in the destination entity");
            Debug.Assert(inverseForeignKeyProperty != null, "Unable to find foreign key for OneToMany relationship");

            var inverseProperty = type.GetInverseProperty(relationshipProperty);

            if (inverseProperty != null)
            {
                EnclosedType inverseEnclosedType;
                var          inverseEntityType = inverseProperty.GetEntityType(out inverseEnclosedType);
                Debug.Assert(inverseEnclosedType == EnclosedType.None, "OneToMany inverse relationship shouldn't be List or Array");
                Debug.Assert(inverseEntityType == type, "OneToMany inverse relationship is not the expected type");
            }

            var keyValue        = originPrimaryKeyProperty.GetValue(element, null);
            var children        = (IEnumerable)relationshipProperty.GetValue(element, null);
            var childrenKeyList = new List <object>();

            if (children != null)
            {
                foreach (var child in children)
                {
                    var childKey = inversePrimaryKeyProperty.GetValue(child, null);
                    childrenKeyList.Add(childKey);

                    inverseForeignKeyProperty.SetValue(child, keyValue, null);
                    if (inverseProperty != null)
                    {
                        inverseProperty.SetValue(child, element, null);
                    }
                }
            }

            string tableName             = entityType.GetTableName();
            string inverseForeignKeyName = inverseForeignKeyProperty.GetColumnName();
            string inversePrimaryKeyName = inversePrimaryKeyProperty.GetColumnName();

            // Objects already updated, now change the database
            var childrenKeysParams = String.Join(",", childrenKeyList.Select(x => "?"));
            var sqlParams          = new List <object> {
                keyValue
            };

            sqlParams.AddRange(childrenKeyList);
            var query = string.Format("update {0} set {1} = ? where {2} in ({3})",
                                      tableName, inverseForeignKeyName, inversePrimaryKeyName, childrenKeysParams);

            conn.Execute(query, sqlParams.ToArray());

            // Delete previous relationships
            var deleteQuery = string.Format("update {0} set {1} = NULL where {1} == ? and {2} not in ({3})",
                                            tableName, inverseForeignKeyName, inversePrimaryKeyName, childrenKeysParams);

            conn.Execute(deleteQuery, sqlParams.ToArray());
        }
Exemplo n.º 21
0
 /// <summary>
 /// Fetches all the entities of the specified type with the filter and fetches all the relationship
 /// properties of all the returned elements.
 /// </summary>
 /// <returns>List of all the elements of the type T that matches the filter with the children already loaded</returns>
 /// <param name="conn">SQLite Net connection object</param>
 /// <param name="filter">Filter that will be passed to the <c>Where</c> clause when fetching
 /// objects from the database. No relationship properties are allowed in this filter as they
 /// are loaded afterwards</param>
 /// <param name="recursive">If set to <c>true</c> all the relationships with
 /// <c>CascadeOperation.CascadeRead</c> will be loaded recusively.</param>
 /// <typeparam name="T">Entity type where the object should be fetched from</typeparam>
 public static List <T> GetAllWithChildren <T>(this SQLiteConnection conn, Expression <Func <T, bool> > filter = null, bool recursive = false) where T
                                                                                                 #if USING_MVVMCROSS
 : new()
                                                                                                 #else
 : class