private FieldInfo GetFieldToSet(IConventionPropertyBase propertyBase) { if (propertyBase == null || !ConfigurationSource.Convention.Overrides(propertyBase.GetFieldInfoConfigurationSource())) { return(null); } var type = propertyBase.DeclaringType.ClrType; while (type != null) { var fieldInfo = TryMatchFieldName( propertyBase.DeclaringType.Model, type, propertyBase.ClrType, propertyBase.Name); if (fieldInfo != null && (propertyBase.PropertyInfo != null || propertyBase.Name == fieldInfo.GetSimpleMemberName())) { return(fieldInfo); } type = type.GetTypeInfo().BaseType; } return(null); }
/// <summary> /// Sets the <see cref="PropertyAccessMode" /> to use for this property. /// </summary> /// <param name="property"> The property for which to set the access mode. </param> /// <param name="propertyAccessMode"> The <see cref="PropertyAccessMode" />, or null to clear the mode set.</param> /// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param> public static void SetPropertyAccessMode( [NotNull] this IConventionPropertyBase property, PropertyAccessMode?propertyAccessMode, bool fromDataAnnotation = false) => Check.NotNull(property, nameof(property)).AsPropertyBase() .SetPropertyAccessMode( propertyAccessMode, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
private FieldInfo GetFieldToSet(IConventionPropertyBase propertyBase) { if (propertyBase == null || !ConfigurationSource.Convention.Overrides(propertyBase.GetFieldInfoConfigurationSource()) || propertyBase.IsIndexerProperty() || propertyBase.IsShadowProperty()) { return(null); } var entityType = (IConventionEntityType)propertyBase.DeclaringType; var type = entityType.ClrType; var baseTypes = entityType.GetAllBaseTypes().ToArray(); while (type != null) { var fieldInfo = TryMatchFieldName(propertyBase, entityType, type); if (fieldInfo != null && (propertyBase.PropertyInfo != null || propertyBase.Name == fieldInfo.GetSimpleMemberName())) { return(fieldInfo); } type = type.BaseType; entityType = baseTypes.FirstOrDefault(et => et.ClrType == type); } return(null); }
/// <summary> /// Sets the <see cref="PropertyAccessMode" /> to use for this property. /// </summary> /// <param name="property"> The property for which to set the access mode. </param> /// <param name="propertyAccessMode"> The <see cref="PropertyAccessMode" />, or null to clear the mode set.</param> /// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param> public static void SetPropertyAccessMode( [NotNull] this IConventionPropertyBase property, PropertyAccessMode?propertyAccessMode, bool fromDataAnnotation = false) { Check.NotNull(property, nameof(property)); property.SetAnnotation(CoreAnnotationNames.PropertyAccessMode, propertyAccessMode, fromDataAnnotation); }
private static FieldInfo?TryMatchFieldName( IConventionPropertyBase propertyBase, IConventionEntityType?entityType, Type entityClrType) { var propertyName = propertyBase.Name; IReadOnlyDictionary <string, FieldInfo> fields; if (entityType == null) { var newFields = new Dictionary <string, FieldInfo>(StringComparer.Ordinal); foreach (var field in entityClrType.GetRuntimeFields()) { if (!field.IsStatic && !newFields.ContainsKey(field.Name)) { newFields[field.Name] = field; } } fields = newFields; } else { fields = entityType.GetRuntimeFields(); } var sortedFields = fields.OrderBy(p => p.Key, StringComparer.Ordinal).ToArray(); var match = TryMatch(sortedFields, "<", propertyName, ">k__BackingField", null, null, entityClrType, propertyName); if (match == null) { match = TryMatch(sortedFields, propertyName, "", "", propertyBase, null, entityClrType, propertyName); var camelPrefix = char.ToLowerInvariant(propertyName[0]).ToString(); var camelizedSuffix = propertyName.Substring(1); match = TryMatch(sortedFields, camelPrefix, camelizedSuffix, "", propertyBase, match, entityClrType, propertyName); match = TryMatch(sortedFields, "_", camelPrefix, camelizedSuffix, propertyBase, match, entityClrType, propertyName); match = TryMatch(sortedFields, "_", "", propertyName, propertyBase, match, entityClrType, propertyName); match = TryMatch(sortedFields, "m_", camelPrefix, camelizedSuffix, propertyBase, match, entityClrType, propertyName); match = TryMatch(sortedFields, "m_", "", propertyName, propertyBase, match, entityClrType, propertyName); match = TryMatch(sortedFields, "", camelPrefix + camelizedSuffix, "_", propertyBase, match, entityClrType, propertyName); } return(match); }
/// <summary> /// Returns the configuration source for <see cref="PropertyBaseExtensions.GetPropertyAccessMode" />. /// </summary> /// <param name="property"> The property to find configuration source for. </param> /// <returns> The configuration source for <see cref="PropertyBaseExtensions.GetPropertyAccessMode" />. </returns> public static ConfigurationSource?GetPropertyAccessModeConfigurationSource([NotNull] this IConventionPropertyBase property) => property.FindAnnotation(CoreAnnotationNames.PropertyAccessMode)?.GetConfigurationSource();
/// <summary> /// <para> /// Sets the underlying CLR field that this property should use. /// This may be <c>null</c> for shadow properties or if the backing field for the property is not known. /// </para> /// <para> /// Backing fields are normally found by convention as described /// here: http://go.microsoft.com/fwlink/?LinkId=723277. /// This method is useful for setting backing fields explicitly in cases where the /// correct field is not found by convention. /// </para> /// <para> /// By default, the backing field, if one is found or has been specified, is used when /// new objects are constructed, typically when entities are queried from the database. /// Properties are used for all other accesses. This can be changed by calling /// <see cref="SetPropertyAccessMode" />. /// </para> /// </summary> /// <param name="property"> The property for which the backing field should be set. </param> /// <param name="fieldName"> The name of the field to use. </param> /// <param name="fromDataAnnotation"> Indicates whether the configuration was specified using a data annotation. </param> public static void SetField( [NotNull] this IConventionPropertyBase property, [CanBeNull] string fieldName, bool fromDataAnnotation = false) => Check.NotNull(property, nameof(property)).AsPropertyBase() .SetField(fieldName, fromDataAnnotation ? ConfigurationSource.DataAnnotation : ConfigurationSource.Convention);
private static FieldInfo TryMatch( KeyValuePair <string, FieldInfo>[] array, string prefix, string middle, string suffix, IConventionPropertyBase propertyBase, FieldInfo existingMatch, Type entityClrType, string propertyName) { var index = PrefixBinarySearch(array, prefix, 0, array.Length - 1); if (index == -1) { return(existingMatch); } var typeInfo = propertyBase?.ClrType; var length = prefix.Length + middle.Length + suffix.Length; var currentValue = array[index]; while (true) { if (currentValue.Key.Length == length && currentValue.Key.EndsWith(suffix, StringComparison.Ordinal) && currentValue.Key.IndexOf(middle, prefix.Length, StringComparison.Ordinal) == prefix.Length) { var newMatch = typeInfo == null ? currentValue.Value : (typeInfo.IsCompatibleWith(currentValue.Value.FieldType) ? currentValue.Value : null); if (newMatch != null) { if (existingMatch != null && newMatch != existingMatch) { propertyBase.SetOrRemoveAnnotation( CoreAnnotationNames.AmbiguousField, CoreStrings.ConflictingBackingFields( propertyName, entityClrType.ShortDisplayName(), existingMatch.Name, newMatch.Name)); return(null); } return(newMatch); } return(existingMatch); } if (++index == array.Length) { return(existingMatch); } currentValue = array[index]; if (!currentValue.Key.StartsWith(prefix, StringComparison.Ordinal)) { return(existingMatch); } } }