private static void GetOneToManyChildren <T>(this SQLiteConnection conn, ref T element, PropertyInfo relationshipProperty) { var type = typeof(T); EnclosedType enclosedType; var entityType = relationshipProperty.GetEntityType(out enclosedType); Debug.Assert(enclosedType != EnclosedType.None, "OneToMany relationship must be a List or Array"); var currentEntityPrimaryKeyProperty = type.GetPrimaryKey(); Debug.Assert(currentEntityPrimaryKeyProperty != null, "OneToMany relationship origin must have Primary Key"); var otherEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true); Debug.Assert(otherEntityForeignKeyProperty != null, "OneToMany relationship destination must have Foreign Key to the origin class"); var tableMapping = conn.GetMapping(entityType); Debug.Assert(tableMapping != null, "There's no mapping table for OneToMany relationship destination"); var inverseProperty = type.GetInverseProperty(relationshipProperty); IEnumerable 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 softDeleteSql = GetSoftDeleteFilterSql(entityType); if (softDeleteSql != null) { query = String.Concat(query, " AND ", softDeleteSql); } var queryResults = conn.Query(tableMapping, query, primaryKeyValue is Guid ? primaryKeyValue.ToString() : primaryKeyValue); values = CreateEnclosedType(entityType, enclosedType, queryResults); } relationshipProperty.SetValue(element, values, null); if (inverseProperty != null && values != null) { // Establish inverse relationships (we already have that object anyway) foreach (var value in values) { inverseProperty.SetValue(value, element, null); } } }
private static void GetManyToManyChildren <T>(this SQLiteConnection conn, ref 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; var tableMapping = conn.GetMapping(entityType); 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"); Debug.Assert(tableMapping != null, "There's no mapping table defined for ManyToMany relationship origin"); IEnumerable 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.Name, intermediateType.Name, currentEntityForeignKeyProperty.Name); var query = string.Format("SELECT * FROM [{0}] WHERE [{1}] IN ({2})", entityType.Name, otherEntityPrimaryKeyProperty.Name, keysQuery); var queryResults = conn.Query(tableMapping, query, primaryKeyValue); values = CreateEnclosedType(entityType, enclosedType, queryResults); } relationshipProperty.SetValue(element, values, null); }
private static void GetManyToOneChild <T>(this SQLiteConnection conn, ref T element, PropertyInfo relationshipProperty) { var type = typeof(T); EnclosedType enclosedType; var entityType = relationshipProperty.GetEntityType(out enclosedType); Debug.Assert(enclosedType == EnclosedType.None, "ManyToOne relationship cannot be of type List or Array"); var otherEntityPrimaryKeyProperty = entityType.GetPrimaryKey(); Debug.Assert(otherEntityPrimaryKeyProperty != null, "ManyToOne relationship destination must have Primary Key"); var currentEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty); Debug.Assert(currentEntityForeignKeyProperty != null, "ManyToOne relationship origin must have Foreign Key"); var tableMapping = conn.GetMapping(entityType); Debug.Assert(tableMapping != null, "There's no mapping table for OneToMany relationship destination"); object value = null; var foreignKeyValue = currentEntityForeignKeyProperty.GetValue(element, null); if (foreignKeyValue != null) { value = conn.Find(foreignKeyValue, tableMapping); if (IsSoftDeleted(entityType, value)) { value = null; } } relationshipProperty.SetValue(element, value, null); }
private static void UpdateManyToManyForeignKeys(this SQLiteConnection conn, object element, PropertyInfo relationshipProperty) { 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; 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"); 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(); // Check for already existing relationships var childrenPlaceHolders = string.Join(",", Enumerable.Repeat("?", childKeyList.Count)); var currentChildrenQuery = string.Format("select [{0}] from [{1}] where [{2}] == ? and [{0}] in ({3})", otherEntityForeignKeyProperty.GetColumnName(), intermediateType.GetTableName(), currentEntityForeignKeyProperty.GetColumnName(), childrenPlaceHolders); var parameters = new List <object> { primaryKey }; parameters.AddRange(childKeyList); var currentChildKeyList = from object child in conn.Query(conn.GetMapping(intermediateType), currentChildrenQuery, parameters.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.GetTableName(), currentEntityForeignKeyProperty.GetColumnName(), otherEntityForeignKeyProperty.GetColumnName(), childrenPlaceHolders); conn.Execute(deleteQuery, parameters.ToArray()); }
private static void GetOneToManyChildren <T>(this SQLiteConnection conn, ICollection <T> elements, PropertyInfo relationshipProperty) { if (!elements.Any()) { return; } var type = typeof(T); EnclosedType enclosedType; var entityType = relationshipProperty.GetEntityType(out enclosedType); Debug.Assert(enclosedType != EnclosedType.None, "OneToMany relationship must be a List or Array"); var currentEntityPrimaryKeyProperty = type.GetPrimaryKey(); Debug.Assert(currentEntityPrimaryKeyProperty != null, "OneToMany relationship origin must have Primary Key"); var otherEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true); Debug.Assert(otherEntityForeignKeyProperty != null, "OneToMany relationship destination must have Foreign Key to the origin class"); var tableMapping = conn.GetMapping(entityType); Debug.Assert(tableMapping != null, "There's no mapping table for OneToMany relationship destination"); var inverseProperty = type.GetInverseProperty(relationshipProperty); var primaryKeyValues = elements.Select(x => { var fkPropVal = currentEntityPrimaryKeyProperty.GetValue(x, null); return(fkPropVal is Guid ? fkPropVal.ToString() : fkPropVal); }).Where(x => x != null).Distinct().ToList(); if (primaryKeyValues.Count == 0) { return; } var query = String.Format( "SELECT * FROM [{0}] WHERE [{1}] IN ({2})", entityType.GetTableName(), otherEntityForeignKeyProperty.GetColumnName(), String.Join(",", primaryKeyValues.Select(x => "?")) ); var softDeleteSql = GetSoftDeleteFilterSql(entityType); if (softDeleteSql != null) { query = String.Concat(query, " AND ", softDeleteSql); } var children = conn.Query( tableMapping, query, primaryKeyValues.ToArray() ); foreach (var element in elements) { var primaryKeyValue = currentEntityPrimaryKeyProperty.GetValue(element, null); var queryResults = children.Where(x => otherEntityForeignKeyProperty.GetValue(x, null).Equals(primaryKeyValue)).ToList(); IEnumerable values = null; if (primaryKeyValue != null) { values = CreateEnclosedType(entityType, enclosedType, queryResults); } relationshipProperty.SetValue(element, values, null); if (inverseProperty != null && values != null) { // Establish inverse relationships (we already have that object anyway) foreach (var value in values) { inverseProperty.SetValue(value, element, null); } } } }
private static void GetManyToOneChildren <T>(this SQLiteConnection conn, ICollection <T> elements, PropertyInfo relationshipProperty) where T : new() { if (!elements.Any()) { return; } var type = typeof(T); EnclosedType enclosedType; var entityType = relationshipProperty.GetEntityType(out enclosedType); Debug.Assert(enclosedType == EnclosedType.None, "ManyToOne relationship cannot be of type List or Array"); var otherEntityPrimaryKeyProperty = entityType.GetPrimaryKey(); Debug.Assert(otherEntityPrimaryKeyProperty != null, "ManyToOne relationship destination must have Primary Key"); var currentEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty); Debug.Assert(currentEntityForeignKeyProperty != null, "ManyToOne relationship origin must have Foreign Key"); var tableMapping = conn.GetMapping(entityType); Debug.Assert(tableMapping != null, "There's no mapping table for OneToMany relationship destination"); var foreignKeyValues = elements.Select(x => { var fkPropVal = currentEntityForeignKeyProperty.GetValue(x, null); return(fkPropVal is Guid ? fkPropVal.ToString() : fkPropVal); }).Where(x => x != null).Distinct().ToList(); if (foreignKeyValues.Count == 0) { return; } var query = String.Format( "SELECT * FROM \"{0}\" WHERE \"{1}\" IN ({2})", tableMapping.TableName, otherEntityPrimaryKeyProperty.GetColumnName(), String.Join(",", foreignKeyValues.Select(x => "?")) ); var softDeleteSql = GetSoftDeleteFilterSql(entityType); if (softDeleteSql != null) { query = String.Concat(query, " AND ", softDeleteSql); } var foreignValues = conn.Query( tableMapping, query, foreignKeyValues.ToArray() ); foreach (var element in elements) { var foreignKeyValue = currentEntityForeignKeyProperty.GetValue(element, null); object value = null; if (foreignKeyValue != null) { value = foreignValues.SingleOrDefault(x => otherEntityPrimaryKeyProperty.GetValue(x, null).Equals(foreignKeyValue)); } relationshipProperty.SetValue(element, value, null); } }
private static void GetOneToOneChild <T>(this SQLiteConnection conn, ref T element, PropertyInfo relationshipProperty) { var type = typeof(T); EnclosedType enclosedType; var entityType = relationshipProperty.GetEntityType(out enclosedType); Debug.Assert(enclosedType == EnclosedType.None, "OneToOne relationship cannot be of type List or Array"); var currentEntityPrimaryKeyProperty = type.GetPrimaryKey(); var otherEntityPrimaryKeyProperty = entityType.GetPrimaryKey(); Debug.Assert(currentEntityPrimaryKeyProperty != null || otherEntityPrimaryKeyProperty != null, "At least one entity in a OneToOne relationship must have Primary Key"); var currentEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty); var otherEntityForeignKeyProperty = type.GetForeignKeyProperty(relationshipProperty, inverse: true); Debug.Assert(currentEntityForeignKeyProperty != null || otherEntityForeignKeyProperty != null, "At least one entity in a OneToOne relationship must have Foreign Key"); var hasForeignKey = otherEntityPrimaryKeyProperty != null && currentEntityForeignKeyProperty != null; var hasInverseForeignKey = currentEntityPrimaryKeyProperty != null && otherEntityForeignKeyProperty != null; Debug.Assert(hasForeignKey || hasInverseForeignKey, "Missing either ForeignKey or PrimaryKey for a complete OneToOne relationship"); var tableMapping = conn.GetMapping(entityType); Debug.Assert(tableMapping != null, "There's no mapping table for OneToOne relationship"); var inverseProperty = type.GetInverseProperty(relationshipProperty); object value = null; if (hasForeignKey) { var foreignKeyValue = currentEntityForeignKeyProperty.GetValue(element, null); if (foreignKeyValue != null) { value = conn.Find(foreignKeyValue, tableMapping); } } else { var primaryKeyValue = currentEntityPrimaryKeyProperty.GetValue(element, null); if (primaryKeyValue != null) { var query = string.Format("SELECT * FROM [{0}] WHERE [{1}] = ? LIMIT 1", entityType.Name, otherEntityForeignKeyProperty.Name); value = conn.Query(tableMapping, query, primaryKeyValue).FirstOrDefault(); // Its a OneToOne, take only the first } } relationshipProperty.SetValue(element, value, null); if (value != null && inverseProperty != null) { inverseProperty.SetValue(value, element, null); } }