public static bool SuppliedPrimaryKeyValuesMatch( DtoMetadata dtoMetadata, object primaryKeyValue1, object primaryKeyValue2) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); var pkType = primaryKeyPropertyMetadata.Prop.PropertyType; if (pkType == typeof(int?) || pkType == typeof(int)) { return((int?)primaryKeyValue1 == (int?)primaryKeyValue2); } if (pkType == typeof(long?) || pkType == typeof(long)) { return((long?)primaryKeyValue1 == (long?)primaryKeyValue2); } if (pkType == typeof(Guid?) || pkType == typeof(Guid)) { return((Guid?)primaryKeyValue1 == (Guid?)primaryKeyValue2); } throw CreatePrimaryKeyTypeUnsupportedException(primaryKeyPropertyMetadata); }
private IEnumerable <string> GetAllPossibleTypeKeys(DtoMetadata metadata) { var target = new List <string>(); var name = metadata.DtoType.FullName; int matchIndex; do { target.Add(name); if (name.Length > 3 && name.EndsWith("Dto")) { var temp = name.Substring(0, name.Length - 3); target.Add(temp); } matchIndex = name.IndexOf('.'); if (matchIndex >= 0) { name = name.Substring(matchIndex + 1); } } while (matchIndex >= 0); return(target); }
private void DiffEnumerable <T>( T oldObject, T newObject, PropertyMetadata prop, IList <Difference> differences, DtoMetadata metadata, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(); var itemType = GetEnumerableItemType(prop); if (itemType == null) { return; } var getter = prop.Prop.GetGetMethod(); if (getter == null) { return; } DiffEnumerable( oldObject, newObject, oldObject == null ? new ArrayList() : getter.Invoke(oldObject, new object[0]), newObject == null ? new ArrayList() : getter.Invoke(newObject, new object[0]), prop, differences, metadata, itemType, ancestors); }
public static string AppendSelectListAndGetFirstColumnFor( StringBuilder buffer, DtoMetadata metadata, string tableAlias = null) { return(AppendSelectListAndGetFirstColumnFor(buffer, metadata, false, tableAlias)); }
public static bool SuppliedPrimaryKeyValuesMatch( DtoMetadata dtoMetadata, object primaryKeyValue1, object primaryKeyValue2) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); var pkType = primaryKeyPropertyMetadata.Prop.PropertyType; if (pkType == typeof(int?) || pkType == typeof (int)) { return (int?) primaryKeyValue1 == (int?) primaryKeyValue2; } if (pkType == typeof(long?) || pkType == typeof (long)) { return (long?) primaryKeyValue1 == (long?) primaryKeyValue2; } if (pkType == typeof(Guid?) || pkType == typeof (Guid)) { return (Guid?) primaryKeyValue1 == (Guid?) primaryKeyValue2; } throw CreatePrimaryKeyTypeUnsupportedException(primaryKeyPropertyMetadata); }
private void DiffSimpleValue <T>( T oldObject, T newObject, PropertyMetadata prop, IList <Difference> differences, DtoMetadata metadata) { if (oldObject == null || newObject == null) { // Don't need to diff simple values where an object has been created or deleted. return; } var oldValue = prop.GetValue(oldObject); var newValue = prop.GetValue(newObject); if (AreEqual(oldValue, newValue)) { return; } differences.Add(new Difference { OldOwner = oldObject, NewOwner = newObject, OwnerPropertyMetadata = prop, DifferenceType = DifferenceType.Update, OwnerMetadata = metadata, NewValue = newValue, OldValue = oldValue }); }
private void DiffProperties( DtoMetadata metadata, object oldObject, object newObject, IList <Difference> target, IList <Ancestor> ancestors, PropertyMetadata parentPropertyMetadata = null) { ancestors = new List <Ancestor>(ancestors); if ((metadata.IsReferenceData && !metadata.HasUpdateableForeignKeys) || (parentPropertyMetadata != null && parentPropertyMetadata.HasAttribute <ReferenceDataAttribute>() && !parentPropertyMetadata.GetAttribute <ReferenceDataAttribute>().HasUpdateableForeignKeys)) { return; } ancestors.Add(new Ancestor { OldObject = oldObject, NewObject = newObject }); foreach (var prop in metadata.WriteableProperties) { if (metadata.IsReferenceData && !prop.HasAttribute <ForeignKeyReferenceAttribute>()) { continue; } if (parentPropertyMetadata != null && parentPropertyMetadata.HasAttribute <ReferenceDataAttribute>() && !prop.HasAttribute <ForeignKeyReferenceAttribute>()) { continue; } if (prop.IsString || prop.IsNumericType || prop.IsEnum) { DiffSimpleValue(oldObject, newObject, prop, target, metadata); } else if (prop.IsGenericDictionary) { DiffDictionary(oldObject, newObject, prop, target, metadata, ancestors); } else if (prop.IsEnumerable) { DiffEnumerable(oldObject, newObject, prop, target, metadata, ancestors); } else if (prop.IsReferenceType) { DiffReferenceType(oldObject, newObject, prop, target, metadata, ancestors); } else { DiffSimpleValue(oldObject, newObject, prop, target, metadata); } } }
public static string BuildSelectListFor( DtoMetadata metadata, string tableAlias = null) { var buffer = new StringBuilder(); AppendSelectListAndGetFirstColumnFor(buffer, metadata, tableAlias); return(buffer.ToString()); }
private string BuildQueryFor(DtoMetadata metadata) { var columns = SelectListBuilder.BuildSelectListFor(metadata); return(string.Format( "SELECT {0} FROM {1}", columns, metadata.TableName)); }
public static void ValidateAsCompatibleTable(DtoMetadata metadata) { if (metadata.TableName == null) { throw new ArgumentException( string.Format( "Type {0} is not marked with a [Table] attribute. You must mark it with " + "[Table(\"[schema].[tableName]\")] to use it with Dapper.SimpleSave.", metadata.DtoType.FullName), "type"); } if (metadata.DtoType.IsEnum) { return; } var pkMetadata = metadata.PrimaryKey; if (null == pkMetadata) { throw new ArgumentException( string.Format( "Type {0} does not have a property marked with a [PrimaryKey] attribute. You " + "must mark a property of type int?, long? or Guid? with a [PrimaryKey] attribute.", metadata.DtoType.FullName), "type"); } var pkType = pkMetadata.Prop.PropertyType; if (pkType != typeof(int?) && pkType != typeof(long?) && pkType != typeof(Guid?)) { throw new ArgumentException( string.Format( "Primary key properties must be of type int?, long? or Guid? but {0} on {1} " + "is of type {2}. Either change the type of the property or use a different " + "property as the primary key.", pkMetadata.Prop.Name, metadata.DtoType.FullName, pkType.FullName), "type"); } if (pkMetadata.IsReadOnly) { throw new ArgumentException( string.Format( "Primary key properties must be read-write but {0} on {1} is read-only. " + "Make the property read-write or choose a different primary key property.", pkMetadata.Prop.Name, metadata.DtoType.FullName)); } }
public static PropertyMetadata GetValidatedSoftDeleteProperty(DtoMetadata metadata) { if (metadata == null) { throw new ArgumentNullException( "metadata", "Cannot retrieve soft delete marker property for null type metadata."); } if (!metadata.HasSoftDeleteSupport) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the type does not support " + "soft deletion. To support soft deletion add the [SoftDeleteColumn] " + "attribute to a boolean property that indicates whether or not the row " + "corresponding to the object has been soft deleted from the database. " + "You can use either true or false to indicate deletion, depending on " + "value of the optional parameter you supply to [SoftDeleteColumn]. If " + "no value is supplied the default is that false indicates the row has " + "been soft deleted."), "metadata"); } var propertyMetadata = metadata.SoftDeleteProperty; if (propertyMetadata.IsReadOnly) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the soft delete marker property {1} is not writeable.", metadata.DtoType.FullName, propertyMetadata.Prop.Name), "metadata"); } if (propertyMetadata.Prop.PropertyType != typeof (bool)) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the soft delete marker " + "property {1} is of type {2}. This property can only be of type bool. " + "Either change the property type or choose a different property as the " + "soft delete marker.", metadata.DtoType.FullName, propertyMetadata.Prop.Name, propertyMetadata.Prop.PropertyType.FullName), "metadata"); } return propertyMetadata; }
public static void ValidateAsCompatibleTable(DtoMetadata metadata) { if (metadata.TableName == null) { throw new ArgumentException( string.Format( "Type {0} is not marked with a [Table] attribute. You must mark it with " + "[Table(\"[schema].[tableName]\")] to use it with Dapper.SimpleSave.", metadata.DtoType.FullName), "type"); } if (metadata.DtoType.IsEnum) { return; } var pkMetadata = metadata.PrimaryKey; if (null == pkMetadata) { throw new ArgumentException( string.Format( "Type {0} does not have a property marked with a [PrimaryKey] attribute. You " + "must mark a property of type int?, long? or Guid? with a [PrimaryKey] attribute.", metadata.DtoType.FullName), "type"); } var pkType = pkMetadata.Prop.PropertyType; if (pkType != typeof (int?) && pkType != typeof (long?) && pkType != typeof (Guid?)) { throw new ArgumentException( string.Format( "Primary key properties must be of type int?, long? or Guid? but {0} on {1} " + "is of type {2}. Either change the type of the property or use a different " + "property as the primary key.", pkMetadata.Prop.Name, metadata.DtoType.FullName, pkType.FullName), "type"); } if (pkMetadata.IsReadOnly) { throw new ArgumentException( string.Format( "Primary key properties must be read-write but {0} on {1} is read-only. " + "Make the property read-write or choose a different primary key property.", pkMetadata.Prop.Name, metadata.DtoType.FullName)); } }
public static PropertyMetadata GetValidatedSoftDeleteProperty(DtoMetadata metadata) { if (metadata == null) { throw new ArgumentNullException( "metadata", "Cannot retrieve soft delete marker property for null type metadata."); } if (!metadata.HasSoftDeleteSupport) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the type does not support " + "soft deletion. To support soft deletion add the [SoftDeleteColumn] " + "attribute to a boolean property that indicates whether or not the row " + "corresponding to the object has been soft deleted from the database. " + "You can use either true or false to indicate deletion, depending on " + "value of the optional parameter you supply to [SoftDeleteColumn]. If " + "no value is supplied the default is that false indicates the row has " + "been soft deleted."), "metadata"); } var propertyMetadata = metadata.SoftDeleteProperty; if (propertyMetadata.IsReadOnly) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the soft delete marker property {1} is not writeable.", metadata.DtoType.FullName, propertyMetadata.Prop.Name), "metadata"); } if (propertyMetadata.Prop.PropertyType != typeof(bool)) { throw new ArgumentException( string.Format( "Cannot soft delete object of type {0} because the soft delete marker " + "property {1} is of type {2}. This property can only be of type bool. " + "Either change the property type or choose a different property as the " + "soft delete marker.", metadata.DtoType.FullName, propertyMetadata.Prop.Name, propertyMetadata.Prop.PropertyType.FullName), "metadata"); } return(propertyMetadata); }
private static void CheckHasPrimaryKeyProperty( DtoMetadata dtoMetadata, PropertyMetadata primaryKeyPropertyMetadata) { if (null == primaryKeyPropertyMetadata) { throw new ArgumentException(string.Format( "Type {0} cannot be written to the database because it has no primary key defined on it. " + "Add a [PrimaryKey] attribute to the property representing the primary key column. " + "If no primary key is defined on the underlying database table, add a primary key first.", dtoMetadata.DtoType.FullName)); } }
public static bool HaveSamePrimaryKeyValue( DtoMetadata dtoMetadata, object object1, object object2) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); return HasSpecifiedPrimaryKeyValue( dtoMetadata, object1, dtoMetadata.GetPrimaryKeyValueAsObject(object2)); }
public static bool HaveSamePrimaryKeyValue( DtoMetadata dtoMetadata, object object1, object object2) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); return(HasSpecifiedPrimaryKeyValue( dtoMetadata, object1, dtoMetadata.GetPrimaryKeyValueAsObject(object2))); }
public virtual IDtoMetadataBuilder <TDto> AddDtoMetadata(DtoMetadata metadata) { if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } _dtoMetadata = metadata; _dtoMetadata.DtoType = typeof(TDto).GetTypeInfo().FullName !; AllMetadata.Add(_dtoMetadata); return(this); }
public static bool HasSpecifiedPrimaryKeyValue( DtoMetadata dtoMetadata, object obj, object expectedPrimaryKeyValue) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); var objPrimaryKeyValue = dtoMetadata.GetPrimaryKeyValueAsObject(obj); return SuppliedPrimaryKeyValuesMatch( dtoMetadata, objPrimaryKeyValue, expectedPrimaryKeyValue); }
public static bool HasSpecifiedPrimaryKeyValue( DtoMetadata dtoMetadata, object obj, object expectedPrimaryKeyValue) { var primaryKeyPropertyMetadata = dtoMetadata.PrimaryKey; CheckHasPrimaryKeyProperty(dtoMetadata, primaryKeyPropertyMetadata); var objPrimaryKeyValue = dtoMetadata.GetPrimaryKeyValueAsObject(obj); return(SuppliedPrimaryKeyValuesMatch( dtoMetadata, objPrimaryKeyValue, expectedPrimaryKeyValue)); }
private void DiffDictionary( object oldObject, object newObject, PropertyMetadata prop, IList <Difference> differences, DtoMetadata metadata, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(ancestors); var dictType = prop.Prop.PropertyType; var args = dictType.GetGenericArguments(); if (args.Length != 2) { return; } var itemType = args [1]; var values = dictType.GetProperty("Values"); if (values == null) { return; } var getter = values.GetGetMethod(); if (getter == null) { return; } DiffEnumerable( oldObject, newObject, oldObject == null ? new ArrayList() : getter.Invoke(oldObject, new object[0]), newObject == null ? new ArrayList() : getter.Invoke(newObject, new object[0]), prop, differences, metadata, itemType, ancestors); }
private string GetQueryFor( DtoMetadata metadata, string whereClauseColumnName) { lock (_lock) { string query; _metadataQueryCache.TryGetValue(metadata, out query); if (query == null) { query = BuildQueryFor(metadata); _metadataQueryCache.Add(metadata, query); } return(whereClauseColumnName == null ? query + ";" : query + string.Format(" WHERE [{0}] = @columnValue;", whereClauseColumnName)); } }
private void DiffEnumerable( object oldOwner, object newOwner, object oldEnumerable, object newEnumerable, PropertyMetadata prop, IList <Difference> differences, DtoMetadata metadata, Type itemType, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(ancestors); var itemTypeMeta = _dtoMetadataCache.GetMetadataFor(itemType); var pk = itemTypeMeta.PrimaryKey; if (pk == null) { return; } DtoMetadataValidator.ValidateAsCompatibleTable(itemTypeMeta); var oldItems = GetItemDictionary(oldEnumerable as IEnumerable, pk); var newItems = GetItemDictionary(newEnumerable as IEnumerable, pk); // We clear this because if an old item has no PK value then it's // clearly never been saved to the database in the first place, so we // don't want to write SQL to UPDATE or DELETE it. If it exists in // the new items collection, on the other hand, we want to INSERT it. oldItems.ItemsWithNoPkValue.Clear(); AddDifferencesForItemsInOnlyOneCollection( oldOwner, newOwner, metadata, prop, oldItems, newItems, itemTypeMeta, DifferenceType.Deletion, differences, ancestors); AddDifferencesForItemsInOnlyOneCollection( oldOwner, newOwner, metadata, prop, newItems, oldItems, itemTypeMeta, DifferenceType.Insertion, differences, ancestors); AddDifferencesForChangedItems(oldItems, newItems, itemType, differences, ancestors); }
private IEnumerable <dynamic> GetEnumReferenceData(DtoMetadata metadata) { var target = new List <dynamic>(); var enumType = metadata.DtoType; foreach (var value in Enum.GetValues(enumType)) { var valueMember = enumType.GetMember(value.ToString()); var attribute = valueMember[0].GetCustomAttributes(typeof(DescriptionAttribute)).FirstOrDefault() as DescriptionAttribute; var description = attribute != null ? attribute.Description : value.ToString(); target.Add(new { Value = value.ToString(), Caption = string.IsNullOrEmpty(description) ? value.ToString() : description, NumericValue = (int)value }); } return(target); }
private IEnumerable <TResult> GetReferenceData <TResult, TColumnValue>( DtoMetadata metadata, string columnName = null, TColumnValue matchingColumnValue = default(TColumnValue)) { var cacheKey = BaseCacheKey + metadata.DtoType.FullName; if (!string.IsNullOrEmpty(columnName)) { cacheKey += "?" + columnName + "=" + matchingColumnValue; } var result = _cache.Get(cacheKey) as IEnumerable <TResult>; if (result == null) { var query = GetQueryFor(metadata, columnName); dynamic parameters = null; if (columnName != null) { parameters = new ExpandoObject(); parameters.columnValue = matchingColumnValue; } result = Execute(connection => connection.Query <TResult>(query, (object)parameters)); _cache.Set( cacheKey, result, new CacheItemPolicy { AbsoluteExpiration = columnName == null ? DateTimeOffset.Now.AddMinutes(10) : DateTimeOffset.Now.AddMinutes(2) }); } return(result); }
private void AppendPropertyToInsertStatement( Script script, StringBuilder colBuff, StringBuilder valBuff, PropertyMetadata property, ref int index, BaseInsertDeleteOperation operation, ArrayList values, MethodInfo getter, UpdateCommand updateCommand) { object columnValueForUpdate = null; if (property.HasAttribute <ForeignKeyReferenceAttribute>() && null != operation.OwnerMetadata && _dtoMetadataCache.GetValidatedMetadataFor( property.GetAttribute <ForeignKeyReferenceAttribute>().ReferencedDto).TableName == operation.OwnerMetadata.TableName) { columnValueForUpdate = new Func <object>(() => operation.OwnerPrimaryKeyAsObject); values.Add(columnValueForUpdate); } else if (property.HasAttribute <ManyToOneAttribute>() && property.GetAttribute <ManyToOneAttribute>().ForeignKeyTargetColumnName != null) { var propValue = property.GetValue(operation.Value); var propTypeMetadata = _dtoMetadataCache.GetValidatedMetadataFor(property.Prop.PropertyType); if (null != propValue && null != propTypeMetadata) { var targetName = property.GetAttribute <ManyToOneAttribute>().ForeignKeyTargetColumnName; var fkTargetProperty = propTypeMetadata[targetName]; if (fkTargetProperty == null) { throw new ArgumentException(string.Format( "Cannot INSERT foreign key value for non existent target column '{0}'" + " specified from column '{1}'.", targetName, property.ColumnName)); } columnValueForUpdate = new Func <object>(() => fkTargetProperty.GetValue(propValue)); values.Add(columnValueForUpdate); } else { columnValueForUpdate = new Func <object>(() => null); values.Add(columnValueForUpdate); } } else if (property.HasAttribute <ManyToOneAttribute>() || property.HasAttribute <OneToOneAttribute>()) { if (property.HasAttribute <OneToOneAttribute>() && !property.HasAttribute <ForeignKeyReferenceAttribute>()) { // One to one relationship where child table references parent rather than the other way around. // This will be saved along with the child object. return; } object propValue = property.GetValue(operation.Value); DtoMetadata propMetadata = _dtoMetadataCache.GetValidatedMetadataFor(property.Prop.PropertyType); columnValueForUpdate = new Func <object>( () => propValue == null || propMetadata == null ? null : propMetadata.GetPrimaryKeyValueAsObject(propValue)); values.Add(columnValueForUpdate); } else { columnValueForUpdate = getter.Invoke(operation.Value, new object[0]); values.Add(columnValueForUpdate); } if (columnValueForUpdate is Func <object> ) { script.WireUpActions.Add(() => { object newPropertyValue = ((Func <object>)columnValueForUpdate)(); if (CanAssignToProperty(newPropertyValue, property)) { property.Prop.SetValue(operation.Value, newPropertyValue); } }); } updateCommand.AddOperation(new UpdateOperation() { ColumnPropertyMetadata = property, TableName = operation.ValueMetadata.TableName, Value = columnValueForUpdate, ValueMetadata = property.IsString || property.IsNumericType || property.IsEnum || !property.IsReferenceType ? null : _dtoMetadataCache.GetMetadataFor(property.Prop.PropertyType), Owner = operation.Value, OwnerMetadata = operation.ValueMetadata, OwnerPrimaryKeyColumn = operation.ValueMetadata.PrimaryKey.ColumnName, OwnerPropertyMetadata = property }); if (colBuff.Length > 0) { colBuff.Append(@", "); valBuff.Append(@", "); } colBuff.Append("[" + property.ColumnName + "]"); valBuff.Append("{"); valBuff.Append(index); valBuff.Append("}"); ++index; }
private void Diff( object oldOwner, object newOwner, DtoMetadata ownerMetadata, PropertyMetadata property, object oldObject, object newObject, Type handleAsType, IList <Difference> target, bool softDelete, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(ancestors); var metadata = _dtoMetadataCache.GetValidatedMetadataFor(handleAsType); var doReferenceShortcut = false; if (oldObject == null) { if (newObject == null) { return; } doReferenceShortcut = true; } else if (newObject == null) { if (softDelete) { var propertyMetaData = SoftDeleteValidator.GetValidatedSoftDeleteProperty(metadata); var trueIndicatesDeleted = propertyMetaData.Prop.Attribute <SoftDeleteColumnAttribute>().TrueIndicatesDeleted;//GetAttribute<SoftDeleteColumnAttribute>().TrueIndicatesDeleted; target.Add(new Difference() { DifferenceType = DifferenceType.Update, OldValue = !trueIndicatesDeleted, NewValue = trueIndicatesDeleted, ValueMetadata = null, OwnerMetadata = metadata, OwnerPropertyMetadata = propertyMetaData, OldOwner = oldObject, NewOwner = oldObject, Path = ancestors }); return; } doReferenceShortcut = true; } if (doReferenceShortcut) { DiffReferenceType(oldObject, newObject, null, target, metadata, ancestors); } else { if (!PrimaryKeyComparer.HaveSamePrimaryKeyValue(metadata, oldObject, newObject))//objKey != metadata.GetPrimaryKeyValue(newObject)) { if (property == null) { throw new ArgumentException(string.Format( "Cannot diff two objects that do not represent the same row. " + "{0}: primary key does not match - for {1} does not match {2}", handleAsType, metadata.GetPrimaryKeyValueAsObject(oldObject), metadata.GetPrimaryKeyValueAsObject(newObject))); } target.Add(new Difference { OldOwner = oldOwner, NewOwner = newOwner, DifferenceType = DifferenceType.Update, OldValue = oldObject, NewValue = newObject, ValueMetadata = metadata, OwnerPropertyMetadata = property, OwnerMetadata = ownerMetadata, Path = ancestors }); // TODO: Bart - Possibly this may be needed? Hard to see how we wouldn't need to do this //DiffReferenceType(oldObject, null, null, target, metadata); //DiffReferenceType(null, newObject, null, target, metadata); // TODO: Bart - or more likely this, below. DiffProperties(metadata, oldObject, null, target, ancestors, property); DiffProperties(metadata, null, newObject, target, ancestors, property); } else { DiffProperties(metadata, oldObject, newObject, target, ancestors, property); } } }
private void DiffReferenceType <T>( T oldObject, T newObject, PropertyMetadata prop, IList <Difference> differences, DtoMetadata metadata, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(ancestors); MethodInfo getter = null; if (null != prop) { getter = prop.Prop.GetGetMethod(); if (getter == null) { return; } } var oldPropValue = GetPropertyValueFrom(oldObject, getter); var newPropValue = GetPropertyValueFrom(newObject, getter); if (oldPropValue == null) { if (newPropValue == null) { return; } differences.Add(new Difference { OldOwner = oldObject, NewOwner = ReferenceEquals(newObject, newPropValue) ? (object)null : newObject, DifferenceType = DifferenceType.Insertion, OwnerPropertyMetadata = prop, OwnerMetadata = prop == null ? null : metadata, ValueMetadata = prop == null ? metadata : _dtoMetadataCache.GetMetadataFor(prop.Prop.PropertyType), OldValue = null, NewValue = newPropValue, Path = ancestors }); DiffProperties( ReferenceEquals(newObject, newPropValue) ? metadata : _dtoMetadataCache.GetMetadataFor(prop.Prop.PropertyType), ReferenceEquals(newObject, newPropValue) ? oldObject : oldPropValue, ReferenceEquals(newObject, newPropValue) ? newObject : newPropValue, differences, ancestors, prop); } else if (newPropValue == null) { DiffProperties( ReferenceEquals(oldObject, oldPropValue) ? metadata : _dtoMetadataCache.GetMetadataFor(prop.Prop.PropertyType), ReferenceEquals(oldObject, oldPropValue) ? oldObject : oldPropValue, newPropValue, differences, ancestors, prop); differences.Add(new Difference { OldOwner = ReferenceEquals(oldObject, oldPropValue) ? (object)null : oldObject, NewOwner = newObject, DifferenceType = DifferenceType.Deletion, OwnerPropertyMetadata = prop, OwnerMetadata = prop == null ? null : metadata, ValueMetadata = prop == null ? metadata : _dtoMetadataCache.GetMetadataFor(prop.Prop.PropertyType), OldValue = oldPropValue, NewValue = null, Path = ancestors }); } else { ancestors.Add(new Ancestor { OldObject = oldObject, NewObject = newObject }); Diff( ReferenceEquals(oldObject, oldPropValue) ? (object)null : oldObject, ReferenceEquals(newObject, newPropValue) ? (object)null : newObject, metadata, prop, oldPropValue, newPropValue, prop.Prop.PropertyType, differences, false, ancestors); } }
private void AddDifferencesForItemsInOnlyOneCollection( object oldOwner, object newOwner, DtoMetadata metadata, PropertyMetadata prop, ItemLookup items1, ItemLookup items2, DtoMetadata itemTypeMeta, DifferenceType differenceType, IList <Difference> differences, IList <Ancestor> ancestors) { ancestors = new List <Ancestor>(ancestors); ReferenceDataAttribute refData = null; if (itemTypeMeta.HasAttribute <ReferenceDataAttribute>()) { refData = itemTypeMeta.GetAttribute <ReferenceDataAttribute>(); } else if (prop.HasAttribute <ReferenceDataAttribute>()) { refData = prop.GetAttribute <ReferenceDataAttribute>(); } var manyToMany = prop.GetAttribute <ManyToManyAttribute>(); var manyToOne = prop.GetAttribute <ManyToOneAttribute>(); var removed = FindRemovedItems(items1, items2); Action <object> addDifference = item => { if (refData == null && manyToMany == null && manyToOne == null && differenceType == DifferenceType.Deletion) { DiffProperties( itemTypeMeta, item, null, differences, ancestors, prop); } differences.Add(new Difference { OldOwner = oldOwner, NewOwner = newOwner, DifferenceType = differenceType, OwnerPropertyMetadata = prop, OwnerMetadata = metadata, ValueMetadata = itemTypeMeta, NewValue = DifferenceType.Insertion == differenceType ? item : null, OldValue = DifferenceType.Deletion == differenceType ? item : null, Path = ancestors }); if (refData == null && ((manyToMany == null && manyToOne == null) || itemTypeMeta.GetPrimaryKeyValueAsObject(item) == null) && differenceType == DifferenceType.Insertion) { DiffProperties( itemTypeMeta, null, item, differences, ancestors, prop); } }; foreach (var item in removed.ItemsById.Values) { addDifference(item); } foreach (var item in removed.ItemsWithNoPkValue) { addDifference(item); } }
public IEnumerable <BaseCommand> Coalesce(IEnumerable <BaseOperation> operations) { var results = new List <BaseCommand>(); var updates = new List <UpdateOperation>(); var updateColumns = CreateUpdateColumnSet(); DtoMetadata updateMetadata = null; string updateTableName = null; object updatePk = null; foreach (var operation in operations) { if (operation is UpdateOperation) { var update = operation as UpdateOperation; var newMetadata = GetNewUpdateMetadata(update); var newTableName = GetNewUpdateTableName(update); var newPrimaryKeyValue = GetNewUpdatePrimaryKeyValue(update); // If the table name, or row PK changes, we need to apply any UpdateOperations we already have as a new command // then start tracking UpdateOperations afresh, starting with this one. if (updateTableName != newTableName || updateMetadata != newMetadata || !PrimaryKeyComparer.SuppliedPrimaryKeyValuesMatch( newMetadata, updatePk, newPrimaryKeyValue) || updateColumns.Contains(update.ColumnName)) { ValidateUpdateOperation(update); if (null != updateTableName) { ApplyUpdatesSoFarAsNewCommand(results, updates, ref updateTableName, ref updatePk); } updateColumns = CreateUpdateColumnSet(); updateMetadata = newMetadata; updateTableName = newTableName; updatePk = newPrimaryKeyValue; } // TODO: replace UPDATE on same column updateColumns.Add(update.ColumnName); updates.Add(update); } else { ApplyUpdatesSoFarAsNewCommand(results, updates, ref updateTableName, ref updatePk); updateColumns = CreateUpdateColumnSet(); updateMetadata = null; updateTableName = null; updatePk = null; ValidateInsertOrDeleteOperation((BaseInsertDeleteOperation)operation); if (operation is InsertOperation) { results.Add(new InsertCommand(operation as InsertOperation)); } else if (operation is DeleteOperation) { results.Add(new DeleteCommand(operation as DeleteOperation)); } } } if (updates.Count > 0) { ApplyUpdatesSoFarAsNewCommand(results, updates, ref updateTableName, ref updatePk); } return(results); }
public static string AppendSelectListAndGetFirstColumnFor( StringBuilder buffer, DtoMetadata metadata, bool iNeedALeadingComma, string tableAlias = null) { string firstColumn = null; foreach (var property in metadata.AllProperties) { // At the moment this isn't sophisticated enough to drill down through tables. // We might want to add this in future but, given it's currently only used to retrieve // data to populate lists and dropdowns it seems unnecessary. if (!property.Prop.CanWrite || property.HasAttribute <OneToManyAttribute>() || property.HasAttribute <ManyToManyAttribute>() || property.HasAttribute <ManyToOneAttribute>() || property.HasAttribute <OneToOneAttribute>() || property.HasAttribute <SimpleLoadIgnoreAttribute>() || property.IsEnumerable) { continue; } //if (property.HasAttribute<OneToOneAttribute>() // && !string.IsNullOrEmpty(property.GetAttribute<OneToOneAttribute>().ChildForeignKeyColumn)) //{ // continue; //} if (buffer.Length > 0 || iNeedALeadingComma) { buffer.Append(", "); buffer.Append(Environment.NewLine); buffer.Append(" "); } if (!string.IsNullOrEmpty(tableAlias)) { buffer.Append('['); buffer.Append(tableAlias); buffer.Append("]."); } buffer.Append('['); buffer.Append(property.ColumnName); buffer.Append(']'); var columnAlias = property.ColumnName; if (columnAlias != property.Prop.Name && !property.HasAttribute <ManyToOneAttribute>() && !property.HasAttribute <OneToOneAttribute>()) { columnAlias = property.Prop.Name; buffer.Append(" AS ["); buffer.Append(columnAlias); buffer.Append("]"); } if (firstColumn == null) { firstColumn = columnAlias; } } return(firstColumn); }
private void AppendJoin( TypePropertyMap map, int index, TypePropertyMapEntry entry, string aliasForCurrentTable, StringBuilder fromAndJoinsBuff, DtoMetadata metadata, string [] aliases) { var target = map.GetEntryWithMatchingPropertyPreceding(index, entry.Type); if (target == null) { throw new InvalidOperationException( string.Format( "Unable to find any property " + "that fits type '{0}'. Please ensure you have included all the necessary " + "types in your query, and that any type to which '{0}' should be added " + "precedes it in the list of types otherwise, like soldiers killed in " + "Stanley Kubrick's Full Metal Jacket, you will be in a world of s***.", entry.Type)); } fromAndJoinsBuff.Append("LEFT OUTER JOIN "); var targetProperty = target.GetPropertyMetadataFor(entry.Type); if (targetProperty.HasAttribute <ManyToManyAttribute>()) { var manyToMany = targetProperty.GetAttribute <ManyToManyAttribute>(); var linkAlias = AppendTableNameAndAlias(fromAndJoinsBuff, manyToMany.SchemaQualifiedLinkTableName); fromAndJoinsBuff.Append(" ON "); AppendJoinConditionArgument(target, fromAndJoinsBuff, target.Metadata.PrimaryKey, aliases); fromAndJoinsBuff.Append(" = "); AppendJoinConditionArgument(fromAndJoinsBuff, target.Metadata.PrimaryKey, linkAlias); fromAndJoinsBuff.Append(Environment.NewLine); fromAndJoinsBuff.Append("LEFT OUTER JOIN "); var table = metadata.GetAttribute <TableAttribute>(); AppendTableNameAndAlias(fromAndJoinsBuff, table, aliasForCurrentTable); fromAndJoinsBuff.Append(" ON "); AppendJoinConditionArgument(entry, fromAndJoinsBuff, metadata.PrimaryKey, aliases); fromAndJoinsBuff.Append(" = "); AppendJoinConditionArgument(fromAndJoinsBuff, metadata.PrimaryKey, linkAlias); fromAndJoinsBuff.Append(Environment.NewLine); } else { var table = metadata.GetAttribute <TableAttribute>(); AppendTableNameAndAlias(fromAndJoinsBuff, table, aliasForCurrentTable); fromAndJoinsBuff.Append(" ON "); if (targetProperty.HasAttribute <OneToOneAttribute>() && string.IsNullOrEmpty(targetProperty.GetAttribute <OneToOneAttribute>().ChildForeignKeyColumn)) { // Covers situation where foreign key column is on the target table AppendJoinConditionArgument(entry, fromAndJoinsBuff, metadata.PrimaryKey, aliases); fromAndJoinsBuff.Append(" = "); AppendJoinConditionArgument(target, fromAndJoinsBuff, targetProperty, aliases); } else if (targetProperty.HasAttribute <ManyToOneAttribute>()) { var manyToOne = targetProperty.GetAttribute <ManyToOneAttribute>(); var targetColumn = manyToOne.ForeignKeyTargetColumnName; if (string.IsNullOrEmpty(targetColumn)) { AppendJoinConditionArgument(entry, fromAndJoinsBuff, metadata.PrimaryKey, aliases); } else { AppendJoinConditionArgument(entry, fromAndJoinsBuff, targetColumn, aliases); } fromAndJoinsBuff.Append(" = "); AppendJoinConditionArgument(target, fromAndJoinsBuff, targetProperty, aliases); } else if (targetProperty.HasAttribute <OneToOneAttribute>() || targetProperty.HasAttribute <OneToManyAttribute>()) { // Covers situation where foreign key column is on the source table AppendJoinConditionArgument(entry, fromAndJoinsBuff, entry.GetPropertyMetadataFor(target.Type), aliases); fromAndJoinsBuff.Append(" = "); AppendJoinConditionArgument(target, fromAndJoinsBuff, target.Metadata.PrimaryKey, aliases); } else { throw new InvalidOperationException( string.Format( "Unable to generate JOIN condition between types '{0}' and '{1}' because the property '{2}' on '{1}' " + "is not decorated with an attribute indicating its cardinality. Please add a [OneToOne], [OneToMany] " + "[ManyToOne], or [ManyToMany] decoration, as appropriate.", metadata.DtoType, target.Type, targetProperty.Prop.Name)); } fromAndJoinsBuff.Append(Environment.NewLine); } }