/// <summary>
        /// Extension method used to attach the specified entity as modified,
        /// with the specified original state.
        /// </summary>
        /// <typeparam name="T">The entity Type</typeparam>
        /// <param name="objectSet">The ObjectSet to attach to</param>
        /// <param name="current">The current entity state</param>
        /// <param name="original">The original entity state</param>
        public static void AttachAsModified <T>(this ObjectSet <T> objectSet, T current, T original) where T : class
        {
            if (objectSet == null)
            {
                throw new ArgumentNullException(nameof(objectSet));
            }
            if (current == null)
            {
                throw new ArgumentNullException(nameof(current));
            }
            if (original == null)
            {
                throw new ArgumentNullException(nameof(original));
            }

            // Attach the entity if it is not already attached, or if it is already
            // attached, transition to Modified
            EntityState currState = ObjectContextUtilities.GetEntityState(objectSet.Context, current);

            if (currState == EntityState.Detached)
            {
                objectSet.Attach(current);
            }
            else
            {
                objectSet.Context.ObjectStateManager.ChangeObjectState(current, EntityState.Modified);
            }

            ObjectStateEntry stateEntry = ObjectContextUtilities.AttachAsModifiedInternal(current, original, objectSet.Context);

            if (stateEntry.State != EntityState.Modified)
            {
                // Ensure that when we leave this method, the entity is in a
                // Modified state. For example, if current and original are the
                // same, we still need to force the state transition
                objectSet.Context.ObjectStateManager.ChangeObjectState(current, EntityState.Modified);
            }
        }
        /// <summary>
        /// Extension method used to attach the specified entity as modified. This overload
        /// can be used in cases where the entity has a Timestamp member.
        /// </summary>
        /// <typeparam name="T">The entity Type</typeparam>
        /// <param name="objectSet">The ObjectSet to attach to</param>
        /// <param name="entity">The current entity state</param>
        public static void AttachAsModified <T>(this ObjectSet <T> objectSet, T entity) where T : class
        {
            if (objectSet == null)
            {
                throw new ArgumentNullException(nameof(objectSet));
            }
            if (entity == null)
            {
                throw new ArgumentNullException(nameof(entity));
            }

            ObjectContext context   = objectSet.Context;
            EntityState   currState = ObjectContextUtilities.GetEntityState(context, entity);

            if (currState == EntityState.Detached)
            {
                // attach the entity
                objectSet.Attach(entity);
            }

            // transition the entity to the modified state
            context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified);
        }
예제 #3
0
        /// <summary>
        /// Returns a collection of all the <see cref="Attribute"/>s we infer from the metadata associated
        /// with the metadata member corresponding to the given property descriptor
        /// </summary>
        /// <param name="pd">A <see cref="PropertyDescriptor"/> to examine</param>
        /// <returns>A collection of attributes inferred from the metadata in the given descriptor.</returns>
        protected override IEnumerable <Attribute> GetMemberAttributes(PropertyDescriptor pd)
        {
            List <Attribute> attributes = new List <Attribute>();

            // Exclude any EntityState, EntityReference, etc. members
            if (ShouldExcludeEntityMember(pd))
            {
                // for these members, we don't want to do any further
                // attribute inference
                attributes.Add(new ExcludeAttribute());
                return(attributes.ToArray());
            }

            EditableAttribute editableAttribute  = null;
            bool inferRoundtripOriginalAttribute = false;

            bool hasKeyAttribute = (pd.Attributes[typeof(KeyAttribute)] != null);
            bool isEntity        = this.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType;

            if (isEntity)
            {
                EntityType entityType = (EntityType)this.EdmType;
                EdmMember  keyMember  = entityType.KeyMembers.SingleOrDefault(k => k.Name == pd.Name);
                if (keyMember != null && !hasKeyAttribute)
                {
                    attributes.Add(new KeyAttribute());
                    hasKeyAttribute = true;
                }
            }

            EdmProperty member = this.EdmType.Members.SingleOrDefault(p => p.Name == pd.Name) as EdmProperty;

            if (member != null)
            {
                if (hasKeyAttribute)
                {
                    // key members must always be roundtripped
                    inferRoundtripOriginalAttribute = true;

                    // key members that aren't also FK members are non-editable (but allow an initial value)
                    if (!this._keyIsEditable)
                    {
                        editableAttribute = new EditableAttribute(false)
                        {
                            AllowInitialValue = true
                        };
                    }
                }

                // Check if the member is DB generated and add the DatabaseGeneratedAttribute to it if not already present.
                if (pd.Attributes[typeof(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute)] == null)
                {
                    MetadataProperty md = ObjectContextUtilities.GetStoreGeneratedPattern(member);
                    if (md != null)
                    {
                        if ((string)md.Value == "Computed")
                        {
                            attributes.Add(new System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Computed));
                        }
                        else if ((string)md.Value == "Identity")
                        {
                            attributes.Add(new System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity));
                        }
                    }
                }

                // Add implicit ConcurrencyCheck attribute to metadata if ConcurrencyMode is anything other than ConcurrencyMode.None
                Facet facet = member.TypeUsage.Facets.SingleOrDefault(p => p.Name == "ConcurrencyMode");
                if (facet != null && facet.Value != null && (ConcurrencyMode)facet.Value != ConcurrencyMode.None &&
                    pd.Attributes[typeof(ConcurrencyCheckAttribute)] == null)
                {
                    attributes.Add(new ConcurrencyCheckAttribute());
                    inferRoundtripOriginalAttribute = true;
                }

                bool isStringType = pd.PropertyType == typeof(string) || pd.PropertyType == typeof(char[]);

                // Add Required attribute to metadata if the member cannot be null and it is either a reference type or a Nullable<T>
                // unless it is a database generated field
                if (!member.Nullable && (!pd.PropertyType.IsValueType || IsNullableType(pd.PropertyType)) &&
                    !pd.Attributes.OfType <DatabaseGeneratedAttribute>().Any(dga => dga.DatabaseGeneratedOption != DatabaseGeneratedOption.None) &&
                    pd.Attributes[typeof(RequiredAttribute)] == null)
                {
                    attributes.Add(new RequiredAttribute());
                }

                if (isStringType &&
                    pd.Attributes[typeof(StringLengthAttribute)] == null)
                {
                    facet = member.TypeUsage.Facets.SingleOrDefault(p => p.Name == "MaxLength");
                    if (facet != null && facet.Value != null && facet.Value.GetType() == typeof(int))
                    {
                        // need to test for Type int, since the value can also be of type
                        // System.Data.Metadata.Edm.EdmConstants.Unbounded
                        int maxLength = (int)facet.Value;
                        attributes.Add(new StringLengthAttribute(maxLength));
                    }
                }

                bool hasTimestampAttribute = (pd.Attributes[typeof(TimestampAttribute)] != null);

                if (this._timestampMember == member && !hasTimestampAttribute)
                {
                    attributes.Add(new TimestampAttribute());
                    hasTimestampAttribute = true;
                }

                // All members marked with TimestampAttribute (inferred or explicit) need to
                // have [Editable(false)] and [RoundtripOriginal] applied
                if (hasTimestampAttribute)
                {
                    inferRoundtripOriginalAttribute = true;

                    if (editableAttribute == null)
                    {
                        editableAttribute = new EditableAttribute(false);
                    }
                }

                // Add RTO to this member if required. If this type has a timestamp
                // member that member should be the ONLY member we apply RTO to.
                // Dont apply RTO if it is an association member.
                bool isForeignKeyMember = this._foreignKeyMembers != null && this._foreignKeyMembers.Contains(member);
                if ((this._timestampMember == null || this._timestampMember == member) &&
                    (inferRoundtripOriginalAttribute || isForeignKeyMember) &&
                    pd.Attributes[typeof(AssociationAttribute)] == null)
                {
                    if (pd.Attributes[typeof(RoundtripOriginalAttribute)] == null)
                    {
                        attributes.Add(new RoundtripOriginalAttribute());
                    }
                }
            }

            // Add the Editable attribute if required
            if (editableAttribute != null && pd.Attributes[typeof(EditableAttribute)] == null)
            {
                attributes.Add(editableAttribute);
            }

            if (isEntity)
            {
                this.AddAssociationAttributes(pd, attributes);
            }

            return(attributes.ToArray());
        }
예제 #4
0
 /// <summary>
 /// Returns the <see cref="StructuralType"/> that corresponds to the given CLR type
 /// </summary>
 /// <param name="clrType">The CLR type</param>
 /// <returns>The StructuralType that corresponds to the given CLR type</returns>
 public StructuralType GetEdmType(Type clrType)
 {
     return(ObjectContextUtilities.GetEdmType(this.MetadataWorkspace, clrType));
 }