private string GetName(MemberInfo memberInfo, string autoNamePattern, TypeDescriptor typeDescriptor) { if (autoNamePattern == null) { return memberInfo.Name; } return VariableSubstitutor.Substitute(autoNamePattern, (value) => { switch (value) { case "$(PERSISTEDTYPENAME)": return typeDescriptor.PersistedName; case "$(PERSISTEDTYPENAME_LOWER)": return memberInfo.ReflectedType.Name.ToLower(); case "$(TYPENAME)": return memberInfo.ReflectedType.Name; case "$(TYPENAME_LOWER)": return memberInfo.ReflectedType.Name.ToLower(); case "$(PROPERTYNAME)": return memberInfo.Name; default: throw new NotSupportedException(value); } }); }
public PropertyDescriptor(TypeDescriptor declaringTypeDescriptor, Type ownerType, PropertyInfo propertyInfo) { this.OwnerType = ownerType; this.PropertyInfo = propertyInfo; this.DeclaringTypeDescriptor = declaringTypeDescriptor; this.ValueRequiredAttribute = propertyInfo.GetFirstCustomAttribute<ValueRequiredAttribute>(true); this.DefaultValueAttribute = propertyInfo.GetFirstCustomAttribute<DefaultValueAttribute>(true); this.BackReferenceAttribute = propertyInfo.GetFirstCustomAttribute<BackReferenceAttribute>(true); this.RelatedDataAccessObjectsAttribute = propertyInfo.GetFirstCustomAttribute<RelatedDataAccessObjectsAttribute>(true); this.PersistedMemberAttribute = propertyInfo.GetFirstCustomAttribute<PersistedMemberAttribute>(true); this.ComputedMemberAttribute = propertyInfo.GetFirstCustomAttribute<ComputedMemberAttribute>(true); this.ComputedTextMemberAttribute = propertyInfo.GetFirstCustomAttribute<ComputedTextMemberAttribute>(true); this.ForeignObjectConstraintAttribute = propertyInfo.GetFirstCustomAttribute<ForeignObjectConstraintAttribute>(true); if (PersistedMemberAttribute == null) { this.PersistedMemberAttribute = (PersistedMemberAttribute)this.ComputedMemberAttribute ?? this.ComputedTextMemberAttribute; } if (this.PropertyType.IsIntegerType(true) || this.PropertyType.GetUnwrappedNullableType() == typeof(Guid)) { this.AutoIncrementAttribute = propertyInfo.GetFirstCustomAttribute<AutoIncrementAttribute>(true); } this.PrimaryKeyAttribute = this.PropertyInfo.GetFirstCustomAttribute<PrimaryKeyAttribute>(true); this.IsPrimaryKey = this.PrimaryKeyAttribute != null && this.PrimaryKeyAttribute.IsPrimaryKey; this.IndexAttributes = this.PropertyInfo.GetCustomAttributes(typeof(IndexAttribute), true).OfType<IndexAttribute>().ToReadOnlyCollection(); this.UniqueAttribute = this.PropertyInfo.GetFirstCustomAttribute<UniqueAttribute>(true); var named = this.PersistedMemberAttribute ?? this.BackReferenceAttribute ?? (NamedMemberAttribute)this.RelatedDataAccessObjectsAttribute; if (named != null) { this.PersistedName = named.GetName(this, this.DeclaringTypeDescriptor.TypeDescriptorProvider.Configuration.NamingTransforms?.PersistedMemberName); this.PrefixName = named.GetPrefixName(this, this.DeclaringTypeDescriptor.TypeDescriptorProvider.Configuration.NamingTransforms?.PersistedMemberPrefixName); this.SuffixName = named.GetSuffixName(this, this.DeclaringTypeDescriptor.TypeDescriptorProvider.Configuration.NamingTransforms?.PersistedMemberSuffixName); } var expression = this.ComputedMemberAttribute?.GetSetLambdaExpression(this.DeclaringTypeDescriptor.TypeDescriptorProvider.Configuration, this)?.Body.StripConvert(); if (expression?.NodeType == ExpressionType.Assign) { var assignmentExpression = expression as BinaryExpression; if (assignmentExpression.Left.NodeType == ExpressionType.MemberAccess) { var memberAccess = assignmentExpression.Left as MemberExpression; this.ComputedMemberAssignTarget = memberAccess.Member as PropertyInfo; this.ComputedMemberAssignmentValue = assignmentExpression.Right; } } }
public static string Substitute(string pattern, TypeDescriptor typeDescriptor) { var root = false; if (pattern == null) { return typeDescriptor.TypeName; } if (visitedTypes == null) { root = true; visitedTypes = new HashSet<TypeDescriptor>(); } try { return Substitute(pattern, value => { switch (value.ToUpper()) { case "TYPENAME": return typeDescriptor.TypeName; case "TABLENAME": case "PERSISTED_TYPENAME": if (visitedTypes.Contains(typeDescriptor)) { throw new InvalidOperationException("Recursive variable substitution"); } visitedTypes.Add(typeDescriptor); return typeDescriptor.PersistedName; default: throw new NotSupportedException(value); } }); } finally { visitedTypes.Remove(typeDescriptor); Debug.Assert(!root || (root && visitedTypes.Count == 0)); } }
public PropertyDescriptor(TypeDescriptor declaringTypeDescriptor, Type ownerType, PropertyInfo propertyInfo) { this.OwnerType = ownerType; this.PropertyInfo = propertyInfo; this.DeclaringTypeDescriptor = declaringTypeDescriptor; this.ValueRequiredAttribute = propertyInfo.GetFirstCustomAttribute<ValueRequiredAttribute>(true); this.DefaultValueAttribute = propertyInfo.GetFirstCustomAttribute<DefaultValueAttribute>(true); this.BackReferenceAttribute = propertyInfo.GetFirstCustomAttribute<BackReferenceAttribute>(true); this.RelatedDataAccessObjectsAttribute = propertyInfo.GetFirstCustomAttribute<RelatedDataAccessObjectsAttribute>(true); this.PersistedMemberAttribute = propertyInfo.GetFirstCustomAttribute<PersistedMemberAttribute>(true); this.ComputedMemberAttribute = propertyInfo.GetFirstCustomAttribute<ComputedMemberAttribute>(true); this.ComputedTextMemberAttribute = propertyInfo.GetFirstCustomAttribute<ComputedTextMemberAttribute>(true); this.ForeignObjectConstraintAttribute = propertyInfo.GetFirstCustomAttribute<ForeignObjectConstraintAttribute>(true); if (this.PropertyType.IsIntegerType(true) || this.PropertyType.GetUnwrappedNullableType() == typeof(Guid)) { this.AutoIncrementAttribute = propertyInfo.GetFirstCustomAttribute<AutoIncrementAttribute>(true); } this.PrimaryKeyAttribute = this.PropertyInfo.GetFirstCustomAttribute<PrimaryKeyAttribute>(true); this.IsPrimaryKey = this.PrimaryKeyAttribute != null && this.PrimaryKeyAttribute.IsPrimaryKey; if (this.PersistedMemberAttribute != null) { this.PersistedName = this.PersistedMemberAttribute.GetName(this.PropertyInfo, declaringTypeDescriptor); this.PersistedShortName = this.PersistedMemberAttribute.GetShortName(this.PropertyInfo, this.DeclaringTypeDescriptor); } else if (this.BackReferenceAttribute != null) { this.PersistedName = this.BackReferenceAttribute.GetName(this.PropertyInfo, declaringTypeDescriptor); this.PersistedShortName = this.PersistedName; } else if (this.RelatedDataAccessObjectsAttribute != null) { this.PersistedName = propertyInfo.Name; this.PersistedShortName = propertyInfo.Name; } this.IndexAttributes = new ReadOnlyList<IndexAttribute>(this.PropertyInfo.GetCustomAttributes(typeof(IndexAttribute), true).OfType<IndexAttribute>().ToList()); this.UniqueAttribute = this.PropertyInfo.GetFirstCustomAttribute<UniqueAttribute>(true); }
public string GetName(MemberInfo memberInfo, TypeDescriptor typeDescriptor) { return this.GetName(memberInfo, this.Name, typeDescriptor); }
public TypeDescriptorProvider(Type dataAccessModelType, DataAccessModelConfiguration configuration) { this.Configuration = configuration; this.DataAccessModelType = dataAccessModelType; var dataAccessModelAttribute = dataAccessModelType.GetFirstCustomAttribute<DataAccessModelAttribute>(true); if (typeof(DataAccessModel).IsAssignableFrom(dataAccessModelType) && dataAccessModelAttribute == null) { throw new InvalidDataAccessObjectModelDefinition("The DataAccessModel type '{0}' is missing a DataAccessModelAttribute", dataAccessModelType.Name); } foreach (var type in this.DataAccessModelType .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy) .Where(c => c.PropertyType.GetGenericTypeDefinitionOrNull() == typeof(DataAccessObjects<>)) .Select(c => c.PropertyType.GetGenericArguments()[0])) { var currentType = type; while (currentType != null && currentType != typeof(DataAccessObject) && !(currentType.GetGenericTypeDefinitionOrNull() == typeof(DataAccessObject<>))) { var dataAccessObjectAttribute = currentType.GetFirstCustomAttribute<DataAccessObjectAttribute>(false); if (dataAccessObjectAttribute != null) { if (!this.typeDescriptorsByType.ContainsKey(currentType)) { if (!typeof(DataAccessObject).IsAssignableFrom(currentType)) { throw new InvalidDataAccessObjectModelDefinition("The type {0} is decorated with a [DataAccessObject] attribute but does not extend DataAccessObject<T>", currentType.Name); } var typeDescriptor = new TypeDescriptor(this, currentType); if (typeDescriptor.PrimaryKeyProperties.Count(c => c.PropertyType.IsNullableType()) > 0) { throw new InvalidDataAccessObjectModelDefinition("The type {0} illegally defines a nullable primary key", currentType.Name); } this.typeDescriptorsByType[currentType] = typeDescriptor; } } else { throw new InvalidDataAccessObjectModelDefinition("Type '{0}' does not have a DataAccessObject attribute", currentType); } currentType = currentType.BaseType; } } var typesSet = new HashSet<Type>(this.typeDescriptorsByType.Keys); var typesReferenced = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedPropertiesWithoutBackreferences) .Select(c => c.PropertyType) .Where(c => typeof(DataAccessObject).IsAssignableFrom(c)) .Distinct(); var first = typesReferenced.FirstOrDefault(c => !typesSet.Contains(c)); if (first != null) { throw new InvalidDataAccessModelDefinitionException($"Type {first.Name} is referenced but is not declared as a property {dataAccessModelType.Name}"); } // Enums this.enumTypeDescriptorsByType = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedPropertiesWithoutBackreferences) .Select(c => c.PropertyType.GetUnwrappedNullableType()) .Where(c => c.IsEnum) .Distinct() .Select(c => new EnumTypeDescriptor(c)) .ToDictionary(c => c.EnumType, c => c); // Resolve relationships foreach (var typeDescriptor in this.typeDescriptorsByType.Values) { foreach (var propertyDescriptor in typeDescriptor.RelationshipRelatedProperties.Where(c => c.IsRelatedDataAccessObjectsProperty)) { if (typeof(RelatedDataAccessObjects<>).IsAssignableFromIgnoreGenericParameters(propertyDescriptor.PropertyType)) { var currentType = propertyDescriptor.PropertyType; while (currentType != null && currentType.GetGenericTypeDefinitionOrNull() != typeof(RelatedDataAccessObjects<>)) { currentType = currentType?.BaseType; } if (currentType == null) { throw new InvalidOperationException("Code should be unreachable"); } var relatedTypeDescriptor = this.typeDescriptorsByType[currentType.GetSequenceElementType()]; var relatedProperty = relatedTypeDescriptor .RelationshipRelatedProperties .Where(c => c.IsBackReferenceProperty) .SingleOrDefault(c => c.PropertyName == propertyDescriptor.RelatedDataAccessObjectsAttribute.BackReferenceName); relatedProperty = relatedProperty ?? relatedTypeDescriptor .RelationshipRelatedProperties .Where(c => c.IsBackReferenceProperty) .Where(c => !c.PropertyTypeTypeDescriptor.RelationshipRelatedProperties.Any(d => string.Equals(d.RelatedDataAccessObjectsAttribute?.BackReferenceName, c.PropertyName, StringComparison.InvariantCultureIgnoreCase))) .SingleOrDefault(c => typeDescriptor.Type == c.PropertyType); relatedProperty = relatedProperty ?? relatedTypeDescriptor .RelationshipRelatedProperties .Where(c => c.IsBackReferenceProperty) .SingleOrDefault(c => typeDescriptor.Type.IsAssignableFrom(c.PropertyType)); typeDescriptor.AddRelationshipInfo(RelationshipType.ParentOfOneToMany, propertyDescriptor, relatedProperty); relatedTypeDescriptor.AddRelationshipInfo(RelationshipType.ChildOfOneToMany, relatedProperty, propertyDescriptor); } } } // Fill in column names foreach (var typeDescriptor in typeDescriptorsByType.Values) { foreach (var columnInfo in QueryBinder.GetColumnInfos(this, typeDescriptor.PersistedProperties.ToArray())) { typeDescriptor.propertyDescriptorByColumnName[columnInfo.ColumnName] = columnInfo.RootProperty; } } this.ModelTypeDescriptor = new ModelTypeDescriptor(this, dataAccessModelType); }
public TypeRelationshipInfo SetOrCreateRelationshipInfo(TypeDescriptor relatedTypeDescriptor, EntityRelationshipType entityRelationshipType, PropertyDescriptor relatedProperty) { TypeRelationshipInfo retval; if (this.relationshipInfos.TryGetValue(relatedTypeDescriptor, out retval)) { retval.EntityRelationshipType = entityRelationshipType; retval.ReferencingProperty = relatedProperty; retval.RelatedTypeTypeDescriptor = relatedTypeDescriptor; return retval; } retval = new TypeRelationshipInfo(relatedTypeDescriptor, entityRelationshipType, relatedProperty); this.relationshipInfos[relatedTypeDescriptor] = retval; return retval; }
public TypeRelationshipInfo GetRelationshipInfo(TypeDescriptor relatedTypeDescriptor) { TypeRelationshipInfo retval; if (this.relationshipInfos.TryGetValue(relatedTypeDescriptor, out retval)) { return retval; } return null; }
protected virtual IDbCommand BuildUpdateCommand(TypeDescriptor typeDescriptor, DataAccessObject dataAccessObject) { IDbCommand command; SqlCommandValue sqlCommandValue; var updatedProperties = dataAccessObject.GetAdvanced().GetChangedPropertiesFlattened(); if (updatedProperties.Count == 0) { return(null); } var primaryKeys = dataAccessObject.GetAdvanced().GetPrimaryKeysForUpdateFlattened(); var commandKey = new SqlCommandKey(dataAccessObject.GetType(), updatedProperties); if (this.TryGetUpdateCommand(commandKey, out sqlCommandValue)) { command = CreateCommand(); command.CommandText = sqlCommandValue.commandText; FillParameters(command, updatedProperties, primaryKeys); return(command); } var assignments = updatedProperties.Select(c => (Expression) new SqlAssignExpression(new SqlColumnExpression(c.PropertyType, null, c.PersistedName), Expression.Constant(c.Value))).ToReadOnlyList(); Expression where = null; var i = 0; Debug.Assert(primaryKeys.Length > 0); foreach (var primaryKey in primaryKeys) { var currentExpression = Expression.Equal(new SqlColumnExpression(primaryKey.PropertyType, null, primaryKey.PersistedName), Expression.Constant(primaryKey.Value)); if (where == null) { where = currentExpression; } else { where = Expression.And(where, currentExpression); } i++; } var expression = new SqlUpdateExpression(new SqlTableExpression(typeDescriptor.PersistedName), assignments, where); expression = (SqlUpdateExpression)ObjectOperandComparisonExpander.Expand(expression); var result = this.SqlDatabaseContext.SqlQueryFormatterManager.Format(expression, SqlQueryFormatterOptions.Default & ~SqlQueryFormatterOptions.OptimiseOutConstantNulls); command = CreateCommand(); command.CommandText = result.CommandText; CacheUpdateCommand(commandKey, new SqlCommandValue() { commandText = command.CommandText }); FillParameters(command, updatedProperties, primaryKeys); return(command); }
public TypeDescriptorProvider(Type dataAccessModelType) { this.DataAccessModelType = dataAccessModelType; var dataAccessModelAttribute = dataAccessModelType.GetFirstCustomAttribute<DataAccessModelAttribute>(true); if (typeof(DataAccessModel).IsAssignableFrom(dataAccessModelType) && dataAccessModelAttribute == null) { throw new InvalidDataAccessObjectModelDefinition("The DataAccessModel type '{0}' is missing a DataAccessModelAttribute", dataAccessModelType.Name); } foreach (var type in this.DataAccessModelType .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy) .Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(DataAccessObjects<>)) .Select(c => c.PropertyType.GetGenericArguments()[0])) { var currentType = type; while (currentType != null && currentType != typeof(DataAccessObject) && !(currentType.IsGenericType && currentType.GetGenericTypeDefinition() == typeof(DataAccessObject<>))) { var dataAccessObjectAttribute = currentType.GetFirstCustomAttribute<DataAccessObjectAttribute>(false); if (dataAccessObjectAttribute != null) { if (!this.typeDescriptorsByType.ContainsKey(currentType)) { if (!typeof(DataAccessObject).IsAssignableFrom(currentType)) { throw new InvalidDataAccessObjectModelDefinition("The type {0} is decorated with a [DataAccessObject] attribute but does not extend DataAccessObject<T>", currentType.Name); } var typeDescriptor = new TypeDescriptor(this, currentType); if (typeDescriptor.PrimaryKeyProperties.Count(c => c.PropertyType.IsNullableType()) > 0) { throw new InvalidDataAccessObjectModelDefinition("The type {0} illegally defines a nullable primary key", currentType.Name); } this.typeDescriptorsByType[currentType] = typeDescriptor; } } else { throw new InvalidDataAccessObjectModelDefinition("Type '{0}' does not have a DataAccessObject attribute", currentType); } currentType = currentType.BaseType; } } var typesSet = new HashSet<Type>(this.typeDescriptorsByType.Keys); var typesReferenced = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedProperties) .Select(c => c.PropertyType) .Where(c => typeof(DataAccessObject).IsAssignableFrom(c)) .Distinct(); var first = typesReferenced.FirstOrDefault(c => !typesSet.Contains(c)); if (first != null) { throw new InvalidDataAccessModelDefinitionException($"Type {first.Name} is referenced but is not declared as a property {dataAccessModelType.Name}"); } // Enums this.enumTypeDescriptorsByType = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedProperties) .Select(c => c.PropertyType.GetUnwrappedNullableType()) .Where(c => c.IsEnum) .Distinct() .Select(c => new EnumTypeDescriptor(c)) .ToDictionary(c => c.EnumType, c => c); // Resolve relationships foreach (var typeDescriptor in this.typeDescriptorsByType.Values) { foreach (var propertyDescriptor in typeDescriptor.RelatedProperties) { if (typeof(RelatedDataAccessObjects<>).IsAssignableFromIgnoreGenericParameters(propertyDescriptor.PropertyType)) { var currentType = propertyDescriptor.PropertyType; while (!currentType.IsGenericType || (currentType.IsGenericType && currentType.GetGenericTypeDefinition() != typeof(RelatedDataAccessObjects<>))) { currentType = currentType.BaseType; } var relatedType = currentType.GetGenericArguments()[0]; var relatedTypeDescriptor = this.typeDescriptorsByType[relatedType]; var typeRelationshipInfo = typeDescriptor.GetRelationshipInfo(relatedTypeDescriptor); if (typeRelationshipInfo != null) { if (typeRelationshipInfo.RelatedTypeTypeDescriptor != relatedTypeDescriptor) { throw new InvalidDataAccessObjectModelDefinition("The type {0} defines multiple relationships with the type {1}", typeDescriptor.Type.Name, relatedTypeDescriptor.Type.Name); } typeRelationshipInfo.EntityRelationshipType = EntityRelationshipType.ManyToMany; typeRelationshipInfo.RelatedTypeTypeDescriptor = relatedTypeDescriptor; relatedTypeDescriptor.SetOrCreateRelationshipInfo(typeDescriptor, EntityRelationshipType.ManyToMany, null); } else { var relatedProperty = relatedTypeDescriptor.GetRelatedProperty(typeDescriptor.Type); relatedTypeDescriptor.SetOrCreateRelationshipInfo(typeDescriptor, EntityRelationshipType.ChildOfOneToMany, relatedProperty); } } } } foreach (var typeDescriptor in this.typeDescriptorsByType.Values) { foreach (var relationshipInfo in typeDescriptor.GetRelationshipInfos()) { var closedCelationshipInfo = relationshipInfo; if (relationshipInfo.EntityRelationshipType == EntityRelationshipType.ChildOfOneToMany) { if (!typeDescriptor.RelatedProperties.Any(c => c.BackReferenceAttribute != null && c.PropertyType == closedCelationshipInfo.ReferencingProperty.PropertyType)) { throw new InvalidDataAccessObjectModelDefinition("The child type {0} participates in a one-many relationship with the parent type {1} but does not explicitly define a BackReference property", typeDescriptor, relationshipInfo.ReferencingProperty.DeclaringTypeDescriptor); } } } } this.ModelTypeDescriptor = new ModelTypeDescriptor(this, dataAccessModelType); }
public TypeDescriptorProvider(Type dataAccessModelType) { this.DataAccessModelType = dataAccessModelType; var dataAccessModelAttribute = dataAccessModelType.GetFirstCustomAttribute <DataAccessModelAttribute>(true); if (typeof(DataAccessModel).IsAssignableFrom(dataAccessModelType) && dataAccessModelAttribute == null) { throw new InvalidDataAccessObjectModelDefinition("The DataAccessModel type '{0}' is missing a DataAccessModelAttribute", dataAccessModelType.Name); } foreach (var type in this.DataAccessModelType .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy) .Where(c => c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(DataAccessObjects <>)) .Select(c => c.PropertyType.GetGenericArguments()[0])) { var currentType = type; while (currentType != null && currentType != typeof(DataAccessObject) && !(currentType.IsGenericType && currentType.GetGenericTypeDefinition() == typeof(DataAccessObject <>))) { var dataAccessObjectAttribute = currentType.GetFirstCustomAttribute <DataAccessObjectAttribute>(false); if (dataAccessObjectAttribute != null) { if (!typeDescriptorsByType.ContainsKey(currentType)) { if (!typeof(DataAccessObject).IsAssignableFrom(currentType)) { throw new InvalidDataAccessObjectModelDefinition("The type {0} is decorated with a [DataAccessObject] attribute but does not extend DataAccessObject<T>", currentType.Name); } var typeDescriptor = new TypeDescriptor(this, currentType); if (typeDescriptor.PrimaryKeyProperties.Count(c => c.PropertyType.IsNullableType()) > 0) { throw new InvalidDataAccessObjectModelDefinition("The type {0} illegally defines a nullable primary key", currentType.Name); } typeDescriptorsByType[currentType] = typeDescriptor; } } else { throw new InvalidDataAccessObjectModelDefinition("Type '{0}' does not have a DataAccessObject attribute", currentType); } currentType = currentType.BaseType; } } var typesSet = new HashSet <Type>(this.typeDescriptorsByType.Keys); var typesReferenced = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedProperties) .Select(c => c.PropertyType) .Where(c => typeof(DataAccessObject).IsAssignableFrom(c)) .Distinct(); var first = typesReferenced.FirstOrDefault(c => !typesSet.Contains(c)); if (first != null) { throw new InvalidDataAccessModelDefinitionException(string.Format("Type {0} is referenced but is not declared as a property {1}", first.Name, dataAccessModelType.Name)); } // Enums this.enumTypeDescriptorsByType = this.typeDescriptorsByType .Values .SelectMany(c => c.PersistedProperties) .Select(c => c.PropertyType.GetUnwrappedNullableType()) .Where(c => c.IsEnum) .Distinct() .Select(c => new EnumTypeDescriptor(c)) .ToDictionary(c => c.EnumType, c => c); // Resolve relationships foreach (var typeDescriptor in typeDescriptorsByType.Values) { foreach (var propertyDescriptor in typeDescriptor.RelatedProperties) { if (typeof(RelatedDataAccessObjects <>).IsAssignableFromIgnoreGenericParameters(propertyDescriptor.PropertyType)) { var currentType = propertyDescriptor.PropertyType; while (!currentType.IsGenericType || (currentType.IsGenericType && currentType.GetGenericTypeDefinition() != typeof(RelatedDataAccessObjects <>))) { currentType = currentType.BaseType; } var relatedType = currentType.GetGenericArguments()[0]; var relatedTypeDescriptor = this.typeDescriptorsByType[relatedType]; var typeRelationshipInfo = typeDescriptor.GetRelationshipInfo(relatedTypeDescriptor); if (typeRelationshipInfo != null) { if (typeRelationshipInfo.RelatedTypeTypeDescriptor != relatedTypeDescriptor) { throw new InvalidDataAccessObjectModelDefinition("The type {0} defines multiple relationships with the type {1}", typeDescriptor.Type.Name, relatedTypeDescriptor.Type.Name); } typeRelationshipInfo.EntityRelationshipType = EntityRelationshipType.ManyToMany; typeRelationshipInfo.RelatedTypeTypeDescriptor = relatedTypeDescriptor; relatedTypeDescriptor.SetOrCreateRelationshipInfo(typeDescriptor, EntityRelationshipType.ManyToMany, null); } else { var relatedProperty = relatedTypeDescriptor.GetRelatedProperty(typeDescriptor.Type); relatedTypeDescriptor.SetOrCreateRelationshipInfo(typeDescriptor, EntityRelationshipType.ChildOfOneToMany, relatedProperty); } } } } foreach (var typeDescriptor in this.typeDescriptorsByType.Values) { foreach (var relationshipInfo in typeDescriptor.GetRelationshipInfos()) { var closedCelationshipInfo = relationshipInfo; if (relationshipInfo.EntityRelationshipType == EntityRelationshipType.ChildOfOneToMany) { if (!typeDescriptor.RelatedProperties.Any(c => c.BackReferenceAttribute != null && c.PropertyType == closedCelationshipInfo.ReferencingProperty.PropertyType)) { throw new InvalidDataAccessObjectModelDefinition("The child type {0} participates in a one-many relationship with the parent type {1} but does not explicitly define a BackReference property", typeDescriptor, relationshipInfo.ReferencingProperty.DeclaringTypeDescriptor); } } } } this.ModelTypeDescriptor = new ModelTypeDescriptor(this, dataAccessModelType); }
internal string GetName(TypeDescriptor type, string transformString = "") { return VariableSubstituter.SedTransform(VariableSubstituter.Substitute(this.Name ?? type.TypeName, type), transformString); }