예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
 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);
        }
예제 #6
0
        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
            });
        }
예제 #7
0
        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);
                }
            }
        }
예제 #8
0
        public static string BuildSelectListFor(
            DtoMetadata metadata,
            string tableAlias = null)
        {
            var buffer = new StringBuilder();

            AppendSelectListAndGetFirstColumnFor(buffer, metadata, tableAlias);
            return(buffer.ToString());
        }
예제 #9
0
        private string BuildQueryFor(DtoMetadata metadata)
        {
            var columns = SelectListBuilder.BuildSelectListFor(metadata);

            return(string.Format(
                       "SELECT {0} FROM {1}",
                       columns,
                       metadata.TableName));
        }
예제 #10
0
        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);
        }
예제 #14
0
 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));
     }
 }
 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));
        }
예제 #17
0
        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);
        }
예제 #20
0
        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));
        }
예제 #21
0
        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);
        }
예제 #22
0
        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));
            }
        }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
        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);
        }
예제 #26
0
        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;
        }
예제 #27
0
        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);
                }
            }
        }
예제 #28
0
        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);
            }
        }
예제 #29
0
        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);
            }
        }
예제 #30
0
        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);
        }
예제 #31
0
        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);
        }
예제 #32
0
        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);
            }
        }