/// <summary> /// When a complex property on this instance changes, this method performs /// the necessary attach/detach operations for the new instance. /// </summary> /// <param name="metaMember">The complex member.</param> private void AttachComplexObjectInstance(MetaMember metaMember) { // First check if the parent has an existing instance attached for this // property and detach if necessary. string memberName = metaMember.Member.Name; ComplexObject prevInstance = null; if (this.TrackedInstances.TryGetValue(memberName, out prevInstance)) { prevInstance.Detach(); this.TrackedInstances.Remove(memberName); } ComplexObject newInstance = (ComplexObject)metaMember.GetValue(this); if (newInstance != null) { // Attach to the new instance newInstance.Attach(this, memberName, this.OnDataMemberChanging, this.OnDataMemberChanged, this.OnMemberValidationChanged); this.TrackedInstances[memberName] = newInstance; // If the instance has validation errors, we need to sync them into our parent. This // needs to be done as a merge operation, since the parent may already have property // level errors for this member that must be retained. if (newInstance.HasValidationErrors) { foreach (ValidationResult error in ValidationUtilities.ApplyMemberPath(newInstance.ValidationErrors, memberName)) { this.ValidationResultCollection.Add(error); } } } }
private MetaType(Type type) { IEnumerable<PropertyInfo> properties = type.GetProperties(MemberBindingFlags).Where(p => p.GetIndexParameters().Length == 0).OrderBy(p => p.Name); this._isComplex = TypeUtility.IsComplexType(type); bool hasOtherRoundtripMembers = false; foreach (PropertyInfo property in properties) { MetaMember metaMember = new MetaMember(this, property); metaMember.IsCollection = TypeUtility.IsSupportedCollectionType(property.PropertyType); if ((property.GetGetMethod() != null) && (property.GetSetMethod() != null)) { bool isPredefinedType = TypeUtility.IsPredefinedType(property.PropertyType); bool isComplex = TypeUtility.IsSupportedComplexType(property.PropertyType); metaMember.IsDataMember = isPredefinedType || isComplex; metaMember.IsComplex = isComplex; if (isComplex) { this._hasComplexMembers = true; } } if (property.GetGetMethod() != null) { metaMember.RequiresValidation = property.GetCustomAttributes(typeof(ValidationAttribute), true).Length > 0; } if (property.GetCustomAttributes(typeof(AssociationAttribute), false).Length > 0) { metaMember.IsAssociationMember = true; } bool isKeyMember = property.GetCustomAttributes(typeof(KeyAttribute), false).Length > 0; if (isKeyMember) { metaMember.IsKeyMember = true; } if (property.GetCustomAttributes(typeof(CompositionAttribute), false).Length > 0) { this._hasComposition = true; } if (MetaType.IsRoundtripMember(metaMember)) { if (property.GetCustomAttributes(typeof(TimestampAttribute), false).Length != 0 && property.GetCustomAttributes(typeof(ConcurrencyCheckAttribute), false).Length != 0) { // Look for a concurrency version member. There should be only one // (DomainService validation ensures this). this._versionMember = metaMember; } else if (!isKeyMember) { // Look for non-key, non-timestamp roundtripped members. We can skip key members, // since they're read only and cannot be modified by the client anyways. hasOtherRoundtripMembers = true; } metaMember.IsRoundtripMember = true; } metaMember.EditableAttribute = (EditableAttribute)property.GetCustomAttributes(typeof(EditableAttribute), false).SingleOrDefault(); this._metaMembers.Add(property.Name, metaMember); } if ((this._versionMember != null) && !hasOtherRoundtripMembers) { this._shouldRoundtripOriginal = false; } else { this._shouldRoundtripOriginal = true; } if (this._hasComposition) { this._childTypes = type .GetProperties(MemberBindingFlags) .Where(p => p.GetCustomAttributes(typeof(CompositionAttribute), false).Any()) .Select(p => TypeUtility.GetElementType(p.PropertyType)).ToArray(); } this._type = type; this.CalculateAttributesRecursive(type, new HashSet<Type>()); }
private static bool IsMergeableMember(MetaMember metaMember) { return metaMember.IsDataMember && !metaMember.IsAssociationMember && (metaMember.Member.GetCustomAttributes(typeof (MergeAttribute), true).Length == 0 || ((MergeAttribute)metaMember.Member.GetCustomAttributes(typeof (MergeAttribute), true).GetValue(0)).IsMergeable); }
private static bool IsRoundtripMember(MetaMember metaMember) { bool isRoundtripEntity = metaMember.Member.DeclaringType.GetCustomAttributes(typeof(RoundtripOriginalAttribute), true).Length > 0; return metaMember.IsDataMember && !metaMember.IsAssociationMember && (isRoundtripEntity || metaMember.Member.GetCustomAttributes(typeof(RoundtripOriginalAttribute), false).Length != 0); }
/// <summary> /// Visit the specified <see cref="IEntityCollection"/>. /// </summary> /// <param name="entityCollection">The <see cref="IEntityCollection"/>.</param> /// <param name="member">The <see cref="MetaMember"/> for the collection member.</param> protected virtual void VisitEntityCollection(IEntityCollection entityCollection, MetaMember member) { }