private IEnumerable <string> CreateTableUniqueConstraints(Type type, ClusterAttribute clusterAttribute) { List <string> results = new List <string>(); if (PrimaryKeyColumns(type, markedOnly: true).Any()) { results.Add($"CONSTRAINT [U_{GetConstraintBaseName(type)}_Id] UNIQUE {clusterAttribute.Syntax(ClusterOption.Identity)}([Id])"); } results.AddRange(type.GetProperties().Where(pi => pi.HasAttribute <UniqueKeyAttribute>()).Select(pi => { UniqueKeyAttribute attr = pi.GetCustomAttribute <UniqueKeyAttribute>(); return($"CONSTRAINT [U_{GetConstraintBaseName(type)}_{pi.SqlColumnName()}] UNIQUE {attr.GetClusteredSyntax()}([{pi.SqlColumnName()}])"); })); results.AddRange(type.GetCustomAttributes <UniqueKeyAttribute>().Select((u, i) => { string constrainName = (string.IsNullOrEmpty(u.ConstraintName)) ? $"U_{GetConstraintBaseName(type)}_{i}" : u.ConstraintName; return($"CONSTRAINT [{constrainName}] UNIQUE {u.GetClusteredSyntax()}({string.Join(", ", u.ColumnNames.Select(col => $"[{col}]"))})"); })); return(results); }
internal void LoadType(Type type) { if (type == null || type == typeof(object)) { return; } List <PropertyInfoItem> typeProps = null; List <PropertyInfo> props = null; List <Type> innerTypes = null; //double-check lock pattern; optemized thread-safe if (!properties.ContainsKey(type.FullName) && GetPropertyTypeCategory(type) == PropertyTypeCategory.Class) { lock (locker) { innerTypes = new List <Type>(); if (!properties.ContainsKey(type.FullName) && GetPropertyTypeCategory(type) == PropertyTypeCategory.Class) { typeProps = new List <PropertyInfoItem>(); // props = System.ComponentModel.TypeDescriptor.GetProperties(type.GetProperties); props = type.GetProperties().Where(s => s.GetAccessors(false).Any()).ToList(); foreach (var prop in props) { var atts = prop.GetCustomAttributes(false).ToArray(); if (atts.OfType <NotMappedAttribute>().Any()) { continue; } PropertyTypeCategory propTypeCategory = GetPropertyTypeCategory(prop.PropertyType); PropertyInfoItem propInfoItem = new PropertyInfoItem() { Type = type, TypeCategory = propTypeCategory, Property = prop, PropertyName = prop.Name, PropertyType = prop.PropertyType, IsGenericType = prop.PropertyType == typeof(object), IsReadOnly = !prop.CanWrite }; var primaryKeyAtt = atts.OfType <PrimaryKeyAttribute>().FirstOrDefault(); propInfoItem.IsPrimaryKey = null != primaryKeyAtt; var foreignKeyAtts = atts.OfType <ForeignKeyAttribute>(); if (foreignKeyAtts.Any()) { propInfoItem.ForeignKeys = foreignKeyAtts.Cast <ForeignKeyAttribute>().ToList(); } var parentKeyAtts = atts.OfType <ParentKeyAttribute>(); if (parentKeyAtts.Any()) { propInfoItem.ParentKeys = parentKeyAtts.Cast <ParentKeyAttribute>().ToList(); } PropertyAttribute propertyAtt = atts.OfType <PropertyAttribute>().FirstOrDefault(); if (null != propertyAtt) { propInfoItem.Cascade = propertyAtt.Cascade; propInfoItem.IsAutonumber = propertyAtt.AutoNumber; //propInfoItem.ForceAutoNumber = propertyAtt.OverrideAutoNumber; propInfoItem.IsIndexed = propertyAtt.Indexed; propInfoItem.ValuePosition = propertyAtt.Position; propInfoItem.IdentityIncrement = propertyAtt.IdentityIncrement; propInfoItem.IdentitySeed = propertyAtt.IdentitySeed; } RequiredAttribute requiredAtt = atts.OfType <RequiredAttribute>().FirstOrDefault(); propInfoItem.IsRequired = null != requiredAtt; UniqueKeyAttribute uniqueKeyAtt = atts.OfType <UniqueKeyAttribute>().FirstOrDefault(); propInfoItem.IsUnique = null != uniqueKeyAtt; MarkupAttribute markupAtt = atts.OfType <MarkupAttribute>().FirstOrDefault(); propInfoItem.IsMarkup = null != markupAtt; CryptoAttribute cryptoAtt = atts.OfType <CryptoAttribute>().FirstOrDefault(); propInfoItem.Encryption = (null != cryptoAtt) ? cryptoAtt.Method : CryptoMethod.None; ChildrenAttribute childrenAtt = atts.OfType <ChildrenAttribute>().FirstOrDefault(); //InheritedAttribute inheritedAtt = (InheritedAttribute)atts // .FirstOrDefault(s => s.GetType() == typeof(InheritedAttribute)); if (null != childrenAtt) { propInfoItem.ReferenceType = PropertyReferenceType.Children; propInfoItem.Cascade = CascadeOptions.Delete; propInfoItem.ChildParentProperty = childrenAtt.RemoteParentProperty; } GenericTypePropertyAttribute genericTypeAtt = atts.OfType <GenericTypePropertyAttribute>().FirstOrDefault(); if (prop.PropertyType == typeof(object) && null != genericTypeAtt) { propInfoItem.GenericTypeProperty = genericTypeAtt.Name; } //setting reference type if (propInfoItem.ReferenceType != PropertyReferenceType.Children) { if (propTypeCategory == PropertyTypeCategory.None) { propInfoItem.ReferenceType = PropertyReferenceType.None; } else if (foreignKeyAtts.Any()) { if (prop.PropertyType.GetProperties() .Where(s => s.PropertyType == type && null != s.GetCustomAttribute <ForeignKeyAttribute>(false)).Any()) { propInfoItem.ReferenceType = PropertyReferenceType.SelfForeign; } else { propInfoItem.ReferenceType = PropertyReferenceType.Foreign; } } else if (parentKeyAtts.Any()) { propInfoItem.ReferenceType = PropertyReferenceType.Parent; } else { propInfoItem.ReferenceType = PropertyReferenceType.Reference; // PropertyDescriptorCollection propTypeProps = TypeDescriptor.GetProperties(prop.PropertyType); var propTypeProps = type.GetProperties().Where(s => s.GetAccessors(false).Any()).ToList(); System.Collections.IEnumerator propTypePropsItems = propTypeProps.GetEnumerator(); foreach (var propTypeProp in propTypeProps) { var propTypePropAtts = propTypeProp.GetCustomAttributes(false).ToArray(); if (propTypePropAtts.OfType <PrimaryKeyAttribute>().Any()) { propInfoItem.ReferenceType = PropertyReferenceType.Complex; propInfoItem.Cascade = CascadeOptions.Delete; break; } } } } if (propTypeCategory == PropertyTypeCategory.Array) { propInfoItem.CollectionItemType = prop.PropertyType.GetElementType(); } else if (propTypeCategory == PropertyTypeCategory.GenericCollection) { propInfoItem.CollectionItemType = prop.PropertyType.GetGenericArguments().FirstOrDefault(); } typeProps.Add(propInfoItem); if (prop.PropertyType != type && ( propTypeCategory == PropertyTypeCategory.Class || propTypeCategory == PropertyTypeCategory.Array || propTypeCategory == PropertyTypeCategory.GenericCollection)) { if (prop.PropertyType.IsArray && prop.PropertyType.GetArrayRank() == 1) { innerTypes.Add(prop.PropertyType.GetElementType()); } else if (null != prop.PropertyType.GetTypeInfo().GetInterface("ICollection")) { innerTypes.Add(prop.PropertyType.GetGenericArguments().FirstOrDefault()); } else if (prop.PropertyType.GetTypeInfo().IsClass) { innerTypes.Add(prop.PropertyType); } } } properties.Add(type.FullName, typeProps); //if there is no PrimaryKey find a property with name Id and make it PrimaryKey if (!typeProps.Any(s => s.IsPrimaryKey)) { var primaryKeyProperty = typeProps.FirstOrDefault(s => s.PropertyName == "Id"); if (primaryKeyProperty != null) { primaryKeyProperty.IsPrimaryKey = true; if (primaryKeyProperty.PropertyType != typeof(string)) { primaryKeyProperty.IsAutonumber = true; } } } } } //after loading all PropertyInfoItems validate them CheckReservedKeywords(type); //load types of inner reference type properties foreach (var innerType in innerTypes) { LoadType(innerType); } } //else if (properties.ContainsKey(type.FullName)) //{ // typeProps = Properties(type.FullName).ToList(); // props = System.ComponentModel.TypeDescriptor.GetProperties(type); // foreach (PropertyDescriptor prop in props) // { // var propItems = typeProps.Select(s => s.Property).ToArray(); // if (propItems.Contains(prop)) // continue; // var refType = GetPropertyTypeCategory(prop.PropertyType); // if (refType == PropertyTypeCategory.Class || // refType == PropertyTypeCategory.Array || // refType == PropertyTypeCategory.GenericCollection) // { // if (prop.PropertyType.IsArray && prop.PropertyType.GetArrayRank() == 1) // LoadType(prop.PropertyType.GetElementType()); // else if (null != prop.PropertyType.GetInterface("ICollection")) // LoadType(prop.PropertyType.GetGenericArguments().FirstOrDefault()); // else if (prop.PropertyType.IsClass) // LoadType(prop.PropertyType); // } // } //} }