/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> private FieldInfo FindBackingField( IPropertyBase property, IDictionary <Type, Dictionary <string, FieldInfo> > fieldCache) { var typesInHierarchy = property.DeclaringEntityType.ClrType.GetTypesInHierarchy().ToList(); var fieldName = property["BackingField"] as string; if (fieldName != null) { foreach (var type in typesInHierarchy) { var fields = GetFields(type, fieldCache); FieldInfo fieldInfo; if (fields.TryGetValue(fieldName, out fieldInfo)) { if (!fieldInfo.FieldType.GetTypeInfo().IsAssignableFrom(property.GetClrType().GetTypeInfo())) { throw new InvalidOperationException( CoreStrings.BadBackingFieldType( fieldName, fieldInfo.FieldType.ShortDisplayName(), property.DeclaringEntityType.DisplayName(), property.Name, property.GetClrType().ShortDisplayName())); } return(fieldInfo); } } throw new InvalidOperationException( CoreStrings.MissingBackingField(property.DeclaringEntityType.DisplayName(), property.Name, fieldName)); } foreach (var type in typesInHierarchy) { var fields = GetFields(type, fieldCache); var fieldInfo = _fieldMatcher.TryMatchFieldName(property, property.GetPropertyInfo(), fields); if (fieldInfo != null) { return(fieldInfo); } } return(null); }
// TODO: Consider doing this at model building time, but also consider mapping to interfaces // Issue #757 public virtual IEnumerable <Tuple <IProperty, MemberInfo> > MapPropertiesToMembers(IEntityType entityType) { Check.NotNull(entityType, nameof(entityType)); var fieldCache = new Dictionary <Type, Dictionary <string, FieldInfo> >(); var propertyMappings = new List <Tuple <IProperty, MemberInfo> >(); foreach (var property in entityType.GetProperties().Where(p => !p.IsShadowProperty)) { var propertyName = property.Name; MemberInfo memberInfo = null; foreach (var propertyInfo in entityType.ClrType.GetPropertiesInHierarchy(propertyName)) { // TODO: Handle cases where backing field is declared in a different class than the property // Issue #758 Dictionary <string, FieldInfo> fields; if (!fieldCache.TryGetValue(propertyInfo.DeclaringType, out fields)) { fields = propertyInfo.DeclaringType.GetRuntimeFields().ToDictionary(f => f.Name); fieldCache[propertyInfo.DeclaringType] = fields; } var fieldName = property["BackingField"] as string; if (fieldName != null) { FieldInfo fieldInfo; if (!fields.TryGetValue(fieldName, out fieldInfo)) { throw new InvalidOperationException(Strings.MissingBackingField(entityType.Name, propertyName, fieldName)); } if (!fieldInfo.FieldType.GetTypeInfo().IsAssignableFrom(property.ClrType.GetTypeInfo())) { throw new InvalidOperationException( Strings.BadBackingFieldType(fieldName, fieldInfo.FieldType.Name, entityType.Name, propertyName, property.ClrType.Name)); } memberInfo = fieldInfo; } else { memberInfo = _fieldMatcher.TryMatchFieldName(property, propertyInfo, fields); } if (memberInfo != null) { break; } } if (memberInfo == null) { memberInfo = entityType.ClrType.GetPropertiesInHierarchy(propertyName).FirstOrDefault(p => p.SetMethod != null); } if (memberInfo == null) { throw new InvalidOperationException(Strings.NoFieldOrSetter(entityType.Name, propertyName)); } propertyMappings.Add(Tuple.Create(property, memberInfo)); } return(propertyMappings); }