예제 #1
0
        /// <summary>
        /// Determines if the specified EdmMember is a concurrency timestamp.
        /// </summary>
        /// <remarks>Since EF doesn't expose "timestamp" as a first class
        /// concept, we use the below criteria to infer this for ourselves.
        /// </remarks>
        /// <param name="member">The member to check.</param>
        /// <returns>True or false.</returns>
        public static bool IsConcurrencyTimestamp(EdmMember member)
        {
            Facet facet = member.TypeUsage.Facets.SingleOrDefault(p => p.Name == "ConcurrencyMode");

            if (facet == null || facet.Value == null || (ConcurrencyMode)facet.Value != ConcurrencyMode.Fixed)
            {
                return(false);
            }

            facet = member.TypeUsage.Facets.SingleOrDefault(p => p.Name == "FixedLength");
            if (facet == null || facet.Value == null || !((bool)facet.Value))
            {
                return(false);
            }

            facet = member.TypeUsage.Facets.SingleOrDefault(p => p.Name == "MaxLength");
            if (facet == null || facet.Value == null || (int)facet.Value != 8)
            {
                return(false);
            }

            MetadataProperty md = ObjectContextUtilities.GetStoreGeneratedPattern(member);

            if (md == null || facet.Value == null || (string)md.Value != "Computed")
            {
                return(false);
            }

            return(true);
        }
예제 #2
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());
        }