public void Ctor(bool value) { var attribute = new EditableAttribute(value); Assert.Equal(value, attribute.AllowEdit); Assert.Equal(value, attribute.AllowInitialValue); }
public void Can_construct_and_both_AllowEdit_and_AllowInitialValue_are_set(bool value) { var attribute = new EditableAttribute(value); Assert.Equal(value, attribute.AllowEdit); Assert.Equal(value, attribute.AllowInitialValue); }
public void Properties_are_independent(bool value) { var attribute = new EditableAttribute(value); Assert.Equal(value, attribute.AllowEdit); Assert.Equal(value, attribute.AllowInitialValue); attribute.AllowInitialValue = !value; Assert.Equal(value, attribute.AllowEdit); Assert.Equal(!value, attribute.AllowInitialValue); }
public void Properties_ChangingOneProperty_DoesNotAffectTheOther(bool value) { var attribute = new EditableAttribute(value); Assert.Equal(value, attribute.AllowEdit); Assert.Equal(value, attribute.AllowInitialValue); attribute.AllowInitialValue = !value; Assert.Equal(value, attribute.AllowEdit); Assert.Equal(!value, attribute.AllowInitialValue); }
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 attribute inference return attributes.ToArray(); } EditableAttribute editableAttribute = null; bool inferRoundtripOriginalAttribute = false; bool hasKeyAttribute = (pd.Attributes[typeof(KeyAttribute)] != null); bool isEntity = EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType; if (isEntity) { EntityType entityType = (EntityType)EdmType; EdmMember keyMember = entityType.KeyMembers.SingleOrDefault(k => k.Name == pd.Name); if (keyMember != null && !hasKeyAttribute) { attributes.Add(new KeyAttribute()); hasKeyAttribute = true; } } EdmProperty member = 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 (!_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(DatabaseGeneratedAttribute)] == null) { MetadataProperty md = ObjectContextUtilities.GetStoreGeneratedPattern(member); if (md != null) { if ((string)md.Value == "Computed") { attributes.Add(new DatabaseGeneratedAttribute(DatabaseGeneratedOption.Computed)); } else if ((string)md.Value == "Identity") { attributes.Add(new DatabaseGeneratedAttribute(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 metdata if the member cannot be null and it is either a reference type or a Nullable<T> if (!member.Nullable && (!pd.PropertyType.IsValueType || IsNullableType(pd.PropertyType)) && 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 (_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 = _foreignKeyMembers != null && _foreignKeyMembers.Contains(member); if ((_timestampMember == null || _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) { AddAssociationAttributes(pd, attributes); } return attributes.ToArray(); }
/// <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"/>.</param> /// <returns>A collection of attributes inferred from metadata in the given descriptor.</returns> protected override IEnumerable<Attribute> GetMemberAttributes(PropertyDescriptor pd) { List<Attribute> attributes = new List<Attribute>(); MetaDataMember member = this._metaType.DataMembers.Where(p => p.Name == pd.Name).SingleOrDefault(); if (member != null) { EditableAttribute editableAttribute = null; bool hasKeyAttribute = (pd.Attributes[typeof(KeyAttribute)] != null); if (member.IsPrimaryKey && !hasKeyAttribute) { attributes.Add(new KeyAttribute()); hasKeyAttribute = true; } // Check if the member is DB generated and add the DatabaseGeneratedAttribute to it if not already present. if (member.IsDbGenerated && pd.Attributes[typeof(DatabaseGeneratedAttribute)] == null) { if (member.AutoSync == AutoSync.OnInsert) { attributes.Add(new DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)); } else if (member.AutoSync == AutoSync.Always) { attributes.Add(new DatabaseGeneratedAttribute(DatabaseGeneratedOption.Computed)); } } if (hasKeyAttribute && !this._keyIsEditable) { editableAttribute = new EditableAttribute(false) { AllowInitialValue = true }; } if (member.IsAssociation && pd.Attributes[typeof(System.ComponentModel.DataAnnotations.AssociationAttribute)] == null) { System.ComponentModel.DataAnnotations.AssociationAttribute assocAttrib = this.TypeDescriptionContext.CreateAssociationAttribute(member); attributes.Add(assocAttrib); } // Add Required attribute to metdata if the member cannot be null and it is either a reference type or a Nullable<T> bool isStringType = pd.PropertyType == typeof(string) || pd.PropertyType == typeof(char[]); if (!member.CanBeNull && (!pd.PropertyType.IsValueType || IsNullableType(pd.PropertyType)) && pd.Attributes[typeof(RequiredAttribute)] == null) { attributes.Add(new RequiredAttribute()); } // Add implicit ConcurrencyCheck attribute to metadata if UpdateCheck is anything other than UpdateCheck.Never if (member.UpdateCheck != UpdateCheck.Never && pd.Attributes[typeof(ConcurrencyCheckAttribute)] == null) { attributes.Add(new ConcurrencyCheckAttribute()); } bool hasTimestampAttribute = (pd.Attributes[typeof(TimestampAttribute)] != null); if (member.IsVersion && !hasTimestampAttribute) { attributes.Add(new TimestampAttribute()); hasTimestampAttribute = true; } // All members marked with TimestampAttribute (inferred or explicit) need to // have [Editable(false)] applied if (hasTimestampAttribute && editableAttribute == null) { editableAttribute = new EditableAttribute(false); } // Add RoundtripOriginal attribute to this member unless // - this entity has a timestamp member, in which case that member should be the ONLY // member we apply RTO to. // - the member is marked with AssociationAttribute if (!member.IsAssociation && pd.Attributes[typeof(System.ComponentModel.DataAnnotations.AssociationAttribute)] == null && (this._metaType.VersionMember == null || member.IsVersion)) { if (pd.Attributes[typeof(RoundtripOriginalAttribute)] == null) { attributes.Add(new RoundtripOriginalAttribute()); } } if (isStringType && member.DbType != null && member.DbType.Length > 0 && pd.Attributes[typeof(StringLengthAttribute)] == null) { InferStringLengthAttribute(member.DbType, attributes); } // Add EditableAttribute if required if (editableAttribute != null && pd.Attributes[typeof(EditableAttribute)] == null) { attributes.Add(editableAttribute); } } return attributes.ToArray(); }
public void GetBindingMetadata_EditableAttributeTrue_SetsReadOnlyFalse() { // Arrange var provider = new DataAnnotationsMetadataProvider(); var editable = new EditableAttribute(allowEdit: true); var attributes = new Attribute[] { editable }; var key = ModelMetadataIdentity.ForType(typeof(string)); var context = new BindingMetadataProviderContext(key, new ModelAttributes(attributes)); // Act provider.GetBindingMetadata(context); // Assert Assert.False(context.BindingMetadata.IsReadOnly); }
protected virtual IEnumerable<Attribute> GetEntityMemberAttributes(PropertyDescriptor propertyDescriptor) { if (_classMetadata == null) return null; var attributes = new List<Attribute>(); //KeyAttributes if (_classMetadata.Identifier != null) { foreach (Column id in _identifierCols) { if (id.Name == propertyDescriptor.Name) { if (propertyDescriptor.Attributes[typeof(KeyAttribute)] == null) { attributes.Add(new KeyAttribute()); } if (propertyDescriptor.Attributes[typeof(EditableAttribute)] == null) { //An identifier is not editable, sometimes anyway it allow an initial value var editable = new EditableAttribute(false); if (id.Value is SimpleValue) editable.AllowInitialValue = "assigned".Equals(((SimpleValue)id.Value).IdentifierGeneratorStrategy, StringComparison.InvariantCultureIgnoreCase); attributes.Add(editable); } break; } } } Property member = _classMetadata.PropertyIterator.FirstOrDefault(x => x.Name == propertyDescriptor.Name); if (member == null) //If ther's no mapping in nhibernate... return attributes; //Required if ((!member.IsNullable) && (propertyDescriptor.PropertyType.IsValueType && (propertyDescriptor.Attributes[typeof(RequiredAttribute)] == null))) { attributes.Add(new RequiredAttribute()); } //Association if (member.Type.IsAssociationType && (propertyDescriptor.Attributes[typeof(AssociationAttribute)] == null)) { string name; string thisKey = ""; string otherkey = ""; if (member.Type.IsCollectionType) { name = propertyDescriptor.ComponentType.FullName + "_" + member.Name; if (member.Type.ReturnedClass.GetGenericArguments().Length != 1) { throw new Exception( String.Format( "The property {0} is not a generic collection as expected (like IList<T>)...", member.Name)); } Type targetClassType = member.Type.ReturnedClass.GetGenericArguments()[0]; foreach (Column col in _identifierCols) { thisKey += (thisKey != "" ? ", " : "") + col.Name; //*****Naming convention**** //Here I'm assuming that the name of each field in the type that holds the foreign key observe //the following structure: string field = member.Name.Replace(Inflector.Pluralize(targetClassType.Name), "") + propertyDescriptor.ComponentType.Name + "_" + col.Name; otherkey += (otherkey != "" ? ", " : "") + field; if (targetClassType.GetProperties(BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(x => x.Name == field) == null) throw new Exception(String.Format("The class {0} doesn't contain a Property named {1}", targetClassType.Name, field)); } } else //Member is a class type { //Key could be composite, cycle every identifier on "the other side" PersistentClass otherMappingClass = _nhibernateConfiguration.GetClassMapping(member.Type.ReturnedClass); foreach (Column col in otherMappingClass.Key.ColumnIterator) { //Naming Convention: //The name of each foreign key field be MUST BE the name of the class field + "_" + the name of the key field in the targetclass thisKey += (thisKey != "" ? ", " : "") + member.Name + "_" + col.Name; otherkey += (otherkey != "" ? ", " : "") + col.Name; } //Check: this name MUST ALWAYS BE the same on the both side of a bi-directional association name = member.Type.ReturnedClass.FullName + "_" + Inflector.Pluralize(member.PersistentClass.NodeName); } //CHECK: When do you want to add an IncludeAttribute ? if (!_classMetadata.IsLazy) { var incAttr = new IncludeAttribute(); attributes.Add(incAttr); } var attribute = new AssociationAttribute( name, thisKey, otherkey ); Type fromParent = ForeignKeyDirection.ForeignKeyFromParent.GetType(); attribute.IsForeignKey = fromParent.IsInstanceOfType(((IAssociationType)member.Type).ForeignKeyDirection); attributes.Add(attribute); } //RoundtripOriginal if (member == _classMetadata.Version) attributes.Add(new RoundtripOriginalAttribute()); return attributes.ToArray(); }