private void ValidateTable(Type entityType, IEnumerable <SchemaTableColumn> schemaTableColumns, string tableName) { var error = new Dictionary <string, bool>(); var propertiesMapping = entityType .GetRuntimeProperties() .Where(x => x.IsPrimitive()) .OrderBy(_conventions.GetColumnOrderOrDefault) .ToDictionary(_conventions.GetColumnName, x => x); var columns = propertiesMapping.Keys.ToArray(); // Ensure we have the same number of columns and they all have the same name if (schemaTableColumns.Count() != columns.Length) { error["ColumnCount_Mismatch"] = true; } if (!schemaTableColumns.All(x => columns.Contains(x.ColumnName))) { error["ColumnName_Mismatch"] = true; } if (error.Any()) { throw new InvalidOperationException(string.Format(Resources.SchemaTableColumnsMismatch, entityType.Name)); } // Gets all the constraints var schemaTableColumnConstraintsMapping = GetSchemaTableColumnConstraintsMapping(tableName, columns); var primaryKeyPropertiesMapping = _conventions.GetPrimaryKeyPropertyInfos(entityType).ToDictionary(_conventions.GetColumnName, x => x); // Gets all the foreign keys var foreignKeyPropertyInfosMapping = entityType .GetRuntimeProperties() .Where(x => x.IsComplex()) .Select(pi => _conventions.GetForeignKeyPropertyInfos(entityType, pi.PropertyType) .ToDictionary(_conventions.GetColumnName, x => pi)) .SelectMany(x => x) .ToDictionary(x => x.Key, x => x.Value); // Validate all the columns foreach (var schemaTableColumn in schemaTableColumns) { var columnName = schemaTableColumn.ColumnName; var propertyInfo = propertiesMapping[columnName]; // Property type var columnDataType = DbHelper.MapToType(schemaTableColumn.DataType); if (columnDataType != propertyInfo.PropertyType) { error["PropertyType_Mismatch"] = true; } // Property order if (!error.Any()) { var columnAttribute = propertyInfo.GetCustomAttribute <ColumnAttribute>(); if (columnAttribute != null && columnAttribute.Order != -1) { var order = schemaTableColumn.OrdinalPosition; // This is cant be a simple 'schemaTableColumn.OrdinalPosition != columnAttribute.Order' to check for a mismatch... // if the type has foreign composite keys, the foreign keys will have an ordering attribute that matches the one on the // foreign entity primary keys, not necessarily the ones that are in the sql database if (foreignKeyPropertyInfosMapping.ContainsKey(columnName)) { var foreignPropertyInfo = foreignKeyPropertyInfosMapping[columnName]; if (_conventions.HasCompositePrimaryKey(foreignPropertyInfo.PropertyType)) { order = schemaTableColumn.OrdinalPosition - (schemaTableColumn.OrdinalPosition - columnAttribute.Order); } } if (order != columnAttribute.Order) { error["OrdinalPosition_Mismatch"] = true; } } } // Property constraints if (!error.Any()) { var requiredAttribute = propertyInfo.GetCustomAttribute <RequiredAttribute>(); var canBeNull = !propertyInfo.PropertyType.IsValueType || Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null; if (canBeNull && schemaTableColumn.IsNullable == "NO") { if (requiredAttribute == null && !primaryKeyPropertiesMapping.ContainsKey(columnName)) { error["IsNullable_Mismatch"] = true; } } if (schemaTableColumnConstraintsMapping != null && schemaTableColumnConstraintsMapping.ContainsKey(columnName)) { var constraint = schemaTableColumnConstraintsMapping[columnName]; switch (constraint) { case SchemaTableConstraintType.NotNull: { if (requiredAttribute == null) { error["IsNullable_Mismatch"] = true; } break; } case SchemaTableConstraintType.PrimaryKey: { if (!primaryKeyPropertiesMapping.ContainsKey(columnName)) { error["PrimaryKey_Mismatch"] = true; } break; } } } } // Property length if (!error.Any()) { var stringLengthAttribute = propertyInfo.GetCustomAttribute <StringLengthAttribute>(); if (stringLengthAttribute != null) { if (schemaTableColumn.CharacterMaximunLength != stringLengthAttribute.MaximumLength) { error["CharacterMaximunLength_Mismatch"] = true; } } } if (error.Any()) { throw new InvalidOperationException(string.Format(Resources.SchemaTableColumnsMismatch, entityType.Name)); } } }