/// <summary> /// Initializes a new instance of the <see cref="SqlTypeInfo"/> class. /// </summary> /// <param name="type">The table type.</param> /// <param name="adapter">The adapter used to generate SQL commands.</param> public SqlTypeInfo(Type type, ISqlAdapter adapter) { Type = type; Adapter = adapter ?? SqlAdapter.GetAdapter(ExtraCrud.Dialect); TableAttribute tableAttr = type.GetCustomAttribute <TableAttribute>(false); BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.NonPublic; // Determine the TableName, Adapter, and BindingFlags bool inherit = false; if (tableAttr == null) { var tableAttr2 = type.GetCustomAttribute <System.ComponentModel.DataAnnotations.Schema.TableAttribute>(false); if (tableAttr2 != null && !string.IsNullOrWhiteSpace(tableAttr2.Schema)) { TableName = tableAttr2.Name; if (!string.IsNullOrWhiteSpace(tableAttr2.Schema)) { Schema = tableAttr2.Schema.Trim(); } } else { TableName = type.Name; } } else { TableName = string.IsNullOrWhiteSpace(tableAttr.Name) ? type.Name : tableAttr.Name; if (tableAttr.DeclaredOnly) { flags |= BindingFlags.DeclaredOnly; Attributes |= SqlTableAttributes.DeclaredOnly; } if (tableAttr.InheritAttributes) { inherit = true; Attributes |= SqlTableAttributes.InheritAttributes; } if (!string.IsNullOrWhiteSpace(tableAttr.Schema)) { Schema = tableAttr.Schema.Trim(); } } FullyQualifiedTableName = TableName; if (Schema != null) { FullyQualifiedTableName = Schema + "." + TableName; } // Filter properties and iterate them for primary keys PropertyInfo[] properties = type.GetProperties(flags); PropertyInfo[] validProperties = properties.Where(ExtraCrud.IsValidProperty).Where(prop => { return(prop.GetCustomAttribute <NotMappedAttribute>(inherit) == null && prop.GetCustomAttribute <System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute>(inherit) == null); }).ToArray(); if (!validProperties.Any()) { throw new InvalidOperationException(type.FullName + " does not have any valid properties."); } ReadOnlyAttribute readOnlyAttr = type.GetCustomAttribute <ReadOnlyAttribute>(false); if (readOnlyAttr != null) { Attributes |= SqlTableAttributes.IgnoreInsert | SqlTableAttributes.IgnoreUpdate | SqlTableAttributes.IgnoreDelete; } else { var editableAttr = type.GetCustomAttribute <System.ComponentModel.DataAnnotations.EditableAttribute>(false); AutoSyncAttribute autoSyncAttr = type.GetCustomAttribute <AutoSyncAttribute>(false); if (autoSyncAttr != null) { if (autoSyncAttr.SyncUpdate) { Attributes |= SqlTableAttributes.UpdateAutoSync; } if (autoSyncAttr.SyncInsert) { Attributes |= SqlTableAttributes.InsertAutoSync; } } if (editableAttr != null) { if (!editableAttr.AllowEdit) { Attributes |= SqlTableAttributes.IgnoreUpdate; } if (editableAttr.AllowInitialValue) { Attributes |= SqlTableAttributes.IgnoreInsert; } } else { IgnoreInsertAttribute noInserts = type.GetCustomAttribute <IgnoreInsertAttribute>(false); if (noInserts != null) { Attributes |= SqlTableAttributes.IgnoreInsert; } IgnoreUpdateAttribute noUpdates = type.GetCustomAttribute <IgnoreUpdateAttribute>(false); if (noUpdates != null) { Attributes |= SqlTableAttributes.IgnoreUpdate; } } IgnoreDeleteAttribute noDeletes = type.GetCustomAttribute <IgnoreDeleteAttribute>(false); if (noDeletes != null) { Attributes |= SqlTableAttributes.IgnoreDelete; } } // Determine primary key List <SqlColumn> keys = new List <SqlColumn>(); List <SqlColumn> columns = new List <SqlColumn>(); int autoKeyCount = 0; for (int i = 0; i < validProperties.Length; i++) { PropertyInfo prop = validProperties[i]; string columnName = null; ColumnAttribute columnAttr = prop.GetCustomAttribute <ColumnAttribute>(inherit); if (columnAttr != null) { columnName = columnAttr.Name; } else { var columnAttr2 = prop.GetCustomAttribute <System.ComponentModel.DataAnnotations.Schema.ColumnAttribute>(inherit); if (columnAttr2 != null) { columnName = columnAttr2.Name; } } string propName = Adapter.QuoteIdentifier(prop.Name); SqlColumn column = new SqlColumn(prop, string.IsNullOrWhiteSpace(columnName) ? propName : Adapter.QuoteIdentifier(columnName), propName, i); KeyAttribute keyAttr = prop.GetCustomAttribute <KeyAttribute>(inherit); if (keyAttr != null) { if (keyAttr.AutoIncrement) { autoKeyCount++; } column.Attributes = keyAttr.AutoIncrement ? SqlColumnAttributes.AutoKey : SqlColumnAttributes.Key; } else { var keyAttrCm = prop.GetCustomAttribute <System.ComponentModel.DataAnnotations.KeyAttribute>(inherit); if (keyAttrCm != null) { var requiredAttr = prop.GetCustomAttribute <System.ComponentModel.DataAnnotations.RequiredAttribute>(inherit); if (requiredAttr != null && ExtraCrud.IsValidAutoIncrementType(prop.PropertyType)) { column.Attributes |= SqlColumnAttributes.Key; } else { column.Attributes |= SqlColumnAttributes.AutoKey; autoKeyCount++; } } } if (column.IsKey) { keys.Add(column); if (!prop.CanRead || !prop.GetMethod.IsPublic || prop.GetMethod.IsStatic) { Attributes |= SqlTableAttributes.IgnoreInsert | SqlTableAttributes.IgnoreUpdate | SqlTableAttributes.IgnoreDelete; } } columns.Add(column); } if (keys.Count == 0) { string quotedId = Adapter.QuoteIdentifier("ID"); SqlColumn key = columns.FirstOrDefault(c => string.Equals(c.ColumnName, quotedId, StringComparison.OrdinalIgnoreCase)); if (key == null) { quotedId = Adapter.QuoteIdentifier(type.Name + "ID"); key = columns.Where(c => c.ColumnName.Equals(quotedId, StringComparison.OrdinalIgnoreCase)).OrderByDescending(c => c.ColumnName.Contains(type.Name)).FirstOrDefault(); } if (key != null) { var requiredAttr = key.Property.GetCustomAttribute <System.ComponentModel.DataAnnotations.RequiredAttribute>(inherit); if (requiredAttr == null) { key.Attributes |= SqlColumnAttributes.AutoKey; } else { key.Attributes |= SqlColumnAttributes.Key; } keys.Add(key); } else { KeyColumns = Constants.SqlColumnsEmpty; } } if (keys.Count != 0) { KeyColumns = keys.ToArray(); if (KeyColumns.Count == 1 && KeyColumns[0].IsAutoKey && ExtraCrud.IsValidAutoIncrementType(KeyColumns[0].Type)) { AutoKeyColumn = KeyColumns[0]; } else if (autoKeyCount != 0 && KeyColumns.Count != autoKeyCount) { throw new InvalidOperationException(Type.FullName + " cannot have a both a composite key and an autoincrement key."); } else { // remove SqlColumnAttributes.AutoKey from all key columns SqlColumnAttributes invertedAutoKey = ~(SqlColumnAttributes.AutoKey ^ SqlColumnAttributes.Key); foreach (SqlColumn key in KeyColumns) { key.Attributes &= invertedAutoKey; } } } foreach (SqlColumn column in columns.Where(c => !c.IsKey)) { PropertyInfo prop = column.Property; bool selectOnly = !prop.CanRead || !prop.GetMethod.IsPublic || prop.GetMethod.IsStatic; if (selectOnly) { column.Attributes |= SqlColumnAttributes.IgnoreInsert | SqlColumnAttributes.IgnoreUpdate | SqlColumnAttributes.IgnoreDelete; } // Selects IgnoreSelectAttribute selectAttr = prop.GetCustomAttribute <IgnoreSelectAttribute>(inherit); if (selectAttr != null) { column.Attributes |= SqlColumnAttributes.IgnoreSelect; if (selectOnly) { continue; } } else if (selectOnly) { continue; } else { AutoSyncAttribute autoSyncAttr = prop.GetCustomAttribute <AutoSyncAttribute>(inherit); if (autoSyncAttr != null) { if (autoSyncAttr.SyncInsert) { column.Attributes |= SqlColumnAttributes.InsertAutoSync; } if (autoSyncAttr.SyncUpdate) { column.Attributes |= SqlColumnAttributes.UpdateAutoSync; } } if (InsertAutoSync) { column.Attributes |= SqlColumnAttributes.InsertAutoSync; } if (UpdateAutoSync) { column.Attributes |= SqlColumnAttributes.UpdateAutoSync; } } // Deletes MatchDeleteAttribute deleteAttr = prop.GetCustomAttribute <MatchDeleteAttribute>(inherit); if (deleteAttr != null || IgnoreDelete) { column.Attributes |= SqlColumnAttributes.IgnoreDelete; } readOnlyAttr = prop.GetCustomAttribute <ReadOnlyAttribute>(inherit); if (readOnlyAttr != null) { column.Attributes |= SqlColumnAttributes.IgnoreInsert | SqlColumnAttributes.IgnoreUpdate; continue; } var editableAttr = prop.GetCustomAttribute <System.ComponentModel.DataAnnotations.EditableAttribute>(inherit); if (editableAttr != null) { if (!editableAttr.AllowInitialValue) { column.Attributes |= SqlColumnAttributes.IgnoreUpdate; } if (!editableAttr.AllowEdit) { column.Attributes |= SqlColumnAttributes.IgnoreUpdate; } } // Inserts IgnoreInsertAttribute insertAttr = prop.GetCustomAttribute <IgnoreInsertAttribute>(inherit); if (insertAttr != null) { column.Attributes |= SqlColumnAttributes.IgnoreInsert; column.InsertValue = insertAttr.Value; if (insertAttr.AutoSync) { column.Attributes |= SqlColumnAttributes.InsertAutoSync; } } else if (IgnoreInsert) { column.Attributes |= SqlColumnAttributes.IgnoreInsert; } // Updates IgnoreUpdateAttribute ignoreUpdateAttr = prop.GetCustomAttribute <IgnoreUpdateAttribute>(inherit); if (ignoreUpdateAttr != null) { column.Attributes |= SqlColumnAttributes.IgnoreUpdate; column.UpdateValue = ignoreUpdateAttr.Value; if (ignoreUpdateAttr.AutoSync) { column.Attributes |= SqlColumnAttributes.UpdateAutoSync; } } else if (IgnoreUpdate) { column.Attributes = SqlColumnAttributes.IgnoreUpdate; } else { MatchUpdateAttribute matchUpdateAttr = prop.GetCustomAttribute <MatchUpdateAttribute>(inherit); //NOTE: MatchUpdate != IgnoreUpdate if (matchUpdateAttr != null) { column.Attributes |= SqlColumnAttributes.MatchUpdate; column.UpdateValue = matchUpdateAttr.Value; if (matchUpdateAttr.AutoSync) { column.Attributes |= SqlColumnAttributes.UpdateAutoSync; } } } } if (columns.Count == 0) { throw new InvalidOperationException(type.FullName + " does not have any valid properties."); // double check } Columns = columns.ToArray(); EqualityColumns = KeyColumns.Count == 0 || KeyColumns.Count == Columns.Count ? Columns : KeyColumns; UpdateKeyColumns = Columns == EqualityColumns ? Constants.SqlColumnsEmpty : Columns.Where(c => c.IsKey || c.MatchUpdate).ToArray(); DeleteKeyColumns = Columns == EqualityColumns ? Columns : Columns.Where(c => c.IsKey || c.MatchDelete).ToArray(); }
/// <summary> /// Initializes a new instance of the <see cref="SqlTypeInfo"/> class. /// </summary> /// <param name="type">The table type.</param> /// <param name="dialect">The dialect used to generate SQL commands.</param> public SqlTypeInfo(Type type, SqlDialect dialect = SqlDialect.SQLServer) : this(type, SqlAdapter.GetAdapter(dialect)) { }