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); }
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); }
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); }
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); }