private void BuildNestedFields(FieldInfo source, FieldInfo target, IEnumerable<FieldInfo> fields) { var buffer = fields.ToList(); foreach (var field in buffer) { var clone = field.Clone(); if (target.SkipVersion) clone.SkipVersion = true; clone.IsSystem = false; clone.IsLazyLoad = field.IsLazyLoad || target.IsLazyLoad; if (target.IsDeclared) { clone.Name = context.NameBuilder.BuildNestedFieldName(target, field); clone.OriginalName = field.OriginalName; // One-field reference if (target.IsEntity && buffer.Count == 1) { clone.MappingName = target.MappingName; clone.DefaultValue = target.DefaultValue; } else clone.MappingName = context.NameBuilder.BuildMappingName(target, field); } if (target.Fields.Contains(clone.Name)) continue; clone.Parent = target; target.ReflectedType.Fields.Add(clone); if (field.IsStructure || field.IsEntity) { BuildNestedFields(source, clone, field.Fields); foreach (FieldInfo clonedFields in clone.Fields) target.Fields.Add(clonedFields); } else { if (field.Column!=null) clone.Column = BuildInheritedColumn(clone, field.Column); } if (target.IsStructure && clone.IsEntity && !IsAuxiliaryType(clone.ReflectedType)) { var origin = context.Model.Associations .Find(context.Model.Types[field.ValueType], true) .FirstOrDefault(a => a.OwnerField.Equals(field)); if (origin!=null && !clone.IsInherited) { AssociationBuilder.BuildAssociation(context, origin, clone); context.DiscardedAssociations.Add(origin); } } if (!clone.IsStructure && !clone.IsEntitySet && !target.ReflectedType.IsInterface && 0!=(clone.Attributes & FieldAttributes.Indexed)) { var typeDef = context.ModelDef.Types[target.DeclaringType.UnderlyingType]; var attribute = new IndexAttribute(clone.Name); var index = context.ModelDefBuilder.DefineIndex(typeDef, attribute); if (typeDef.Indexes.Contains(index.Name)) throw new DomainBuilderException( string.Format(Strings.ExIndexWithNameXIsAlreadyRegistered, index.Name)); typeDef.Indexes.Add(index); BuildLog.Info(Strings.LogIndexX, index.Name); } } }
private void BuildAssociations() { using (BuildLog.InfoRegion(Strings.LogBuildingX, Strings.Associations)) { PreprocessAssociations(); foreach (var pair in context.PairedAssociations) { if (context.DiscardedAssociations.Contains(pair.First)) { continue; } if (!context.Model.Associations.Contains(pair.First)) { continue; } AssociationBuilder.BuildPairedAssociation(pair.First, pair.Second); } foreach (var ai in context.DiscardedAssociations) { context.Model.Associations.Remove(ai); } context.DiscardedAssociations.Clear(); foreach (var association in context.Model.Associations) { TryAddForeignKeyIndex(association); if (association.IsPaired) { continue; } if (!association.OnOwnerRemove.HasValue) { association.OnOwnerRemove = association.OwnerField.IsEntitySet ? OnRemoveAction.Clear : OnRemoveAction.None; } if (!association.OnTargetRemove.HasValue) { association.OnTargetRemove = OnRemoveAction.Deny; } } BuildAuxiliaryTypes(context.Model.Associations); } }
private FieldInfo BuildDeclaredField(TypeInfo type, FieldDef fieldDef) { BuildLog.Info(Strings.LogBuildingDeclaredFieldXY, type.Name, fieldDef.Name); var fieldInfo = new FieldInfo(type, fieldDef.Attributes) { UnderlyingProperty = fieldDef.UnderlyingProperty, Name = fieldDef.Name, OriginalName = fieldDef.Name, MappingName = fieldDef.MappingName, ValueType = fieldDef.ValueType, ItemType = fieldDef.ItemType, Length = fieldDef.Length, Scale = fieldDef.Scale, Precision = fieldDef.Precision, Validators = fieldDef.Validators, }; if (fieldInfo.IsStructure && DeclaresOnValidate(fieldInfo.ValueType)) { fieldInfo.Validators.Add(new StructureFieldValidator()); } if (fieldInfo.IsEntitySet && DeclaresOnValidate(fieldInfo.ValueType)) { fieldInfo.Validators.Add(new EntitySetFieldValidator()); } type.Fields.Add(fieldInfo); if (fieldInfo.IsEntitySet) { AssociationBuilder.BuildAssociation(context, fieldDef, fieldInfo); return(fieldInfo); } if (fieldInfo.IsEntity) { var fields = context.Model.Types[fieldInfo.ValueType].Fields.Where(f => f.IsPrimaryKey); // Adjusting default value if any if (fields.Count() == 1 && fieldDef.DefaultValue != null) { fieldInfo.DefaultValue = ValueTypeBuilder.AdjustValue(fieldInfo, fields.First().ValueType, fieldDef.DefaultValue); } BuildNestedFields(null, fieldInfo, fields); if (!IsAuxiliaryType(type)) { AssociationBuilder.BuildAssociation(context, fieldDef, fieldInfo); if (type.IsStructure) { fieldInfo.Associations.ForEach(a => context.DiscardedAssociations.Add(a)); } } // Adjusting type discriminator field for references if (fieldDef.IsTypeDiscriminator) { type.Hierarchy.TypeDiscriminatorMap.Field = fieldInfo.Fields.First(); } } if (fieldInfo.IsStructure) { BuildNestedFields(null, fieldInfo, context.Model.Types[fieldInfo.ValueType].Fields); var structureFullTextIndex = context.ModelDef.FullTextIndexes.TryGetValue(fieldInfo.ValueType); if (structureFullTextIndex != null) { var hierarchyTypeInfo = context.Model.Types[fieldInfo.DeclaringType.UnderlyingType]; var structureTypeInfo = context.Model.Types[fieldInfo.ValueType]; var currentIndex = context.ModelDef.FullTextIndexes.TryGetValue(hierarchyTypeInfo.UnderlyingType); if (currentIndex == null) { currentIndex = new FullTextIndexDef(context.ModelDef.Types.TryGetValue(type.UnderlyingType)); context.ModelDef.FullTextIndexes.Add(currentIndex); } currentIndex.Fields.AddRange(structureFullTextIndex.Fields .Select(f => new { fieldInfo.DeclaringType .StructureFieldMapping[new Pair <FieldInfo>(fieldInfo, structureTypeInfo.Fields[f.Name])].Name, f.IsAnalyzed, f.Configuration, f.TypeFieldName }) .Select(g => new FullTextFieldDef(g.Name, g.IsAnalyzed) { Configuration = g.Configuration, TypeFieldName = g.TypeFieldName })); } } if (fieldInfo.IsPrimitive) { fieldInfo.DefaultValue = fieldDef.DefaultValue; fieldInfo.DefaultSqlExpression = fieldDef.DefaultSqlExpression; fieldInfo.Column = BuildDeclaredColumn(fieldInfo); if (fieldDef.IsTypeDiscriminator) { type.Hierarchy.TypeDiscriminatorMap.Field = fieldInfo; } } return(fieldInfo); }
private void PreprocessAssociations() { foreach (var typeInfo in context.Model.Types.Where(t => t.IsEntity && !t.IsAuxiliary)) { // pair integrity escalation and consistency check typesWithProcessedInheritedAssociations.Add(typeInfo); var refFields = typeInfo.Fields.Where(f => f.IsEntity || f.IsEntitySet).ToList(); // check for interface fields foreach (var refField in refFields) { var parentIsPaired = false; var interfaceIsPaired = false; var interfaceAssociations = new List <AssociationInfo>(); var inheritedAssociations = new List <AssociationInfo>(); if (refField.IsDeclared && refField.IsInterfaceImplementation) { var implementedInterfaceFields = typeInfo.FieldMap .GetImplementedInterfaceFields(refField); foreach (var interfaceField in implementedInterfaceFields) { var field = interfaceField; interfaceAssociations.AddRange(field.Associations); interfaceIsPaired |= context.PairedAssociations.Any(pa => field.Associations.Contains(pa.First)); } } if (refField.IsInherited) { var ancestor = typeInfo.GetAncestor(); var field = ancestor.Fields[refField.Name]; inheritedAssociations.AddRange(field.Associations); parentIsPaired |= context.PairedAssociations.Any(pa => field.Associations.Contains(pa.First)); } if (!parentIsPaired && !interfaceIsPaired) { List <Pair <AssociationInfo, string> > pairedToReverse; if (pairedAssociationsToReverse.TryGetValue(typeInfo, out pairedToReverse)) { foreach (var pair in pairedToReverse) { AssociationBuilder.BuildReversedAssociation(context, pair.First, pair.Second); } } var field = refField; var pairedAssociations = context.PairedAssociations .Where(pa => field.Associations.Contains(pa.First)) .ToList(); if (pairedAssociations.Count > 0) { foreach (var paired in pairedAssociations) { paired.First.Ancestors.AddRange(interfaceAssociations); if (paired.First.TargetType.IsInterface || typesWithProcessedInheritedAssociations.Contains(paired.First.TargetType)) { AssociationBuilder.BuildReversedAssociation(context, paired.First, paired.Second); } else { List <Pair <AssociationInfo, string> > pairs; if (!pairedAssociationsToReverse.TryGetValue(paired.First.TargetType, out pairs)) { pairs = new List <Pair <AssociationInfo, string> >(); pairedAssociationsToReverse.Add(paired.First.TargetType, pairs); } pairs.Add(paired); } } continue; } } var fieldCopy = refField; if (!parentIsPaired) { context.PairedAssociations.RemoveAll(pa => fieldCopy.Associations.Contains(pa.First)); } Func <AssociationInfo, bool> associationFilter = a => context.PairedAssociations .Any(pa => a.TargetType.UnderlyingType.IsAssignableFrom(pa.First.OwnerType.UnderlyingType) && pa.Second == a.OwnerField.Name && a.OwnerType == pa.First.TargetType); var associationsToKeep = refField.IsInterfaceImplementation ? refField.Associations .Where(associationFilter) .ToList() : refField.Associations.Count > 1 ? refField.Associations .Where(associationFilter) .ToList() : refField.Associations.ToList(); var associationsToRemove = refField.Associations .Except(associationsToKeep) .ToList(); foreach (var association in associationsToRemove) { context.Model.Associations.Remove(association); refField.Associations.Remove(association); } foreach (var association in associationsToKeep) { var interfaceAssociationsToRemove = interfaceAssociations .Where(ia => ia.OwnerType != association.OwnerType) .ToList(); association.Ancestors.AddRange(interfaceAssociationsToRemove); foreach (var interfaceAssociation in interfaceAssociationsToRemove) { interfaceAssociations.Remove(interfaceAssociation); } } refField.Associations.AddRange(interfaceAssociations); foreach (var association in inheritedAssociations) { if (!refField.Associations.Contains(association.Name)) { refField.Associations.Add(association); } if (!context.Model.Associations.Contains(association)) { context.Model.Associations.Add(association); } } } } }