示例#1
0
        private HierarchyInfo BuildHierarchyInfo(TypeInfo root, HierarchyDef hierarchyDef)
        {
            var key    = BuildKeyInfo(root, hierarchyDef);
            var schema = hierarchyDef.Schema;

            // Optimization. It there is the only class in hierarchy then ConcreteTable schema is applied
            if (schema != InheritanceSchema.ConcreteTable)
            {
                var node = context.DependencyGraph.TryGetNode(hierarchyDef.Root);
                // No dependencies => no descendants
                if (node == null || node.IncomingEdges.Count(e => e.Kind == EdgeKind.Inheritance) == 0)
                {
                    schema = InheritanceSchema.ConcreteTable;
                }
            }

            var typeDiscriminatorField = hierarchyDef.Root.Fields.FirstOrDefault(f => f.IsTypeDiscriminator);
            var typeDiscriminatorMap   = typeDiscriminatorField != null ? new TypeDiscriminatorMap() : null;

            var hierarchy = new HierarchyInfo(root, key, schema, typeDiscriminatorMap)
            {
                Name = root.Name,
            };

            key.Hierarchy = hierarchy; // Setting backreference
            context.Model.Hierarchies.Add(hierarchy);
            return(hierarchy);
        }
示例#2
0
        public void Process(HierarchyDef hierarchyDef, FieldDef fieldDef, KeyAttribute attribute)
        {
            ArgumentValidator.EnsureArgumentIsInRange(attribute.Position, 0, WellKnown.MaxKeyFieldNumber - 1,
                                                      "attribute.Position");

            var keyField = new KeyField(fieldDef.Name, attribute.Direction);

            if (hierarchyDef.KeyFields.Count > attribute.Position)
            {
                var current = hierarchyDef.KeyFields[attribute.Position];
                if (current != null)
                {
                    throw new DomainBuilderException(string.Format(Strings.ExKeyFieldsXAndXHaveTheSamePositionX, current.Name,
                                                                   fieldDef.Name, attribute.Position));
                }

                hierarchyDef.KeyFields[attribute.Position] = keyField;
            }
            else
            {
                // Adding null stubs for not yet processed key fields
                while (hierarchyDef.KeyFields.Count < attribute.Position)
                {
                    hierarchyDef.KeyFields.Add(null);
                }

                // Finally adding target key field at the specified position
                hierarchyDef.KeyFields.Add(keyField);
            }
        }
示例#3
0
        public void ValidateHierarchyEquality(TypeDef @interface, HierarchyDef first, HierarchyDef second)
        {
            // TypeId mode must match
            if (first.IncludeTypeId != second.IncludeTypeId)
            {
                throw new DomainBuilderException(string.Format(
                                                     Strings.ExImplementorsOfXInterfaceBelongToHierarchiesOneOfWhichIncludesTypeIdButAnotherDoesntYZ,
                                                     @interface.Name, first.Root.Name, second.Root.Name));
            }

            // Number of key fields must match
            if (first.KeyFields.Count != second.KeyFields.Count)
            {
                throw new DomainBuilderException(string.Format(
                                                     Strings.ExImplementorsOfXInterfaceBelongToHierarchiesWithDifferentKeyStructureYZ,
                                                     @interface.Name, first.Root.Name, second.Root.Name));
            }

            // Type of each key field must match
            for (int i = 0; i < first.KeyFields.Count; i++)
            {
                var masterField    = first.Root.Fields[first.KeyFields[i].Name];
                var candidateField = second.Root.Fields[second.KeyFields[i].Name];
                if (masterField.ValueType != candidateField.ValueType)
                {
                    throw new DomainBuilderException(string.Format(
                                                         Strings.ExImplementorsOfXInterfaceBelongToHierarchiesWithDifferentKeyStructureYZ,
                                                         @interface.Name, first.Root.Name, second.Root.Name));
                }
            }
        }
        private SequenceInfo BuildSequence(HierarchyDef hierarchyDef, KeyInfo key)
        {
            var seed      = 0L;
            var cacheSize = (long)context.Configuration.KeyGeneratorCacheSize;

            var generatorName = key.GeneratorName;
            KeyGeneratorConfiguration configuration;

            if (keyGeneratorConfigurations.TryGetValue(generatorName, out configuration))
            {
                seed      = configuration.Seed;
                cacheSize = configuration.CacheSize;
            }

            var sequence = new SequenceInfo(generatorName)
            {
                Seed            = seed + cacheSize, // Preallocate keys for the first access
                Increment       = cacheSize,
                MappingDatabase = hierarchyDef.Root.MappingDatabase,
                MappingSchema   = context.Configuration.DefaultSchema,
                MappingName     = context.NameBuilder.BuildSequenceName(key),
            };

            return(sequence);
        }
示例#5
0
        public void Process(HierarchyDef hierarchy, KeyGeneratorAttribute attribute)
        {
            hierarchy.KeyGeneratorKind = attribute.Kind;

            if (!string.IsNullOrEmpty(attribute.Name))
            {
                hierarchy.KeyGeneratorName = attribute.Name;
            }
        }
        public TypeDef ProcessType(Type type)
        {
            var modelDef = context.ModelDef;

            var typeDef = modelDef.Types.TryGetValue(type);

            if (typeDef != null)
            {
                return(typeDef);
            }

            using (BuildLog.InfoRegion(Strings.LogDefiningX, type.GetFullName())) {
                typeDef = DefineType(type);
                if (modelDef.Types.Contains(typeDef.Name))
                {
                    throw new DomainBuilderException(string.Format(Strings.ExTypeWithNameXIsAlreadyDefined, typeDef.Name));
                }

                HierarchyDef hierarchyDef = null;
                if (typeDef.IsEntity)
                {
                    // HierarchyRootAttribute is required for hierarchy root
                    var hra = type.GetAttribute <HierarchyRootAttribute>(AttributeSearchOptions.Default);
                    if (hra != null)
                    {
                        hierarchyDef = DefineHierarchy(typeDef, hra);
                    }
                }

                ProcessProperties(typeDef, hierarchyDef);

                if (typeDef.IsEntity || typeDef.IsInterface)
                {
                    ProcessIndexes(typeDef);
                }

                if (hierarchyDef != null)
                {
                    BuildLog.Info(Strings.LogHierarchyX, typeDef.Name);
                    modelDef.Hierarchies.Add(hierarchyDef);
                }

                modelDef.Types.Add(typeDef);

                ProcessFullTextIndexes(typeDef);

                var validators = type.GetCustomAttributes(false).OfType <IObjectValidator>();
                foreach (var validator in validators)
                {
                    typeDef.Validators.Add(validator);
                }

                return(typeDef);
            }
        }
        public void ProcessProperties(TypeDef typeDef, HierarchyDef hierarchyDef)
        {
            var properties = typeDef.UnderlyingType.GetProperties(
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);

            foreach (var propertyInfo in properties)
            {
                // Domain builder stage-related filter
                if (!IsFieldAvailable(propertyInfo))
                {
                    continue;
                }

                // FieldAttribute presence is required
                var reversedFieldAttributes = GetReversedFieldAttributes <FieldAttribute>(propertyInfo);
                if (reversedFieldAttributes.Count == 0)
                {
                    continue;
                }

                var field = DefineField(propertyInfo, reversedFieldAttributes);

                // Declared & inherited fields must be processed for hierarchy root
                if (hierarchyDef != null)
                {
                    typeDef.Fields.Add(field);
                    BuildLog.Info(Strings.LogFieldX, field.Name);

                    var keyAttributes = propertyInfo.GetAttribute <KeyAttribute>(AttributeSearchOptions.InheritAll);
                    if (keyAttributes != null)
                    {
                        attributeProcessor.Process(hierarchyDef, field, keyAttributes);
                    }
                }
                // Only declared properties must be processed in other cases
                else if (propertyInfo.DeclaringType == propertyInfo.ReflectedType)
                {
                    typeDef.Fields.Add(field);
                    BuildLog.Info(Strings.LogFieldX, field.Name);
                }

                // Checking whether property type is registered in model
                var propertyType = field.UnderlyingProperty.PropertyType;
                if (propertyType.IsGenericParameter)
                {
                    continue;
                }

                if (propertyType.IsSubclassOf(WellKnownOrmTypes.Persistent) && !context.ModelDef.Types.Contains(propertyType))
                {
                    types.Enqueue(propertyType);
                }
            }
        }
示例#8
0
        /// <summary>
        /// Builds name for key generator.
        /// </summary>
        /// <param name="key">Key to build key generator name for.</param>
        /// <param name="hierarchyDef">Hierarchy definition.</param>
        /// <returns>Key generator name</returns>
        public string BuildKeyGeneratorName(KeyInfo key, HierarchyDef hierarchyDef)
        {
            var mappingDatabase        = hierarchyDef.Root.MappingDatabase;
            var databaseSuffixRequired =
                key.GeneratorKind == KeyGeneratorKind.Default &&
                KeyGeneratorFactory.IsSequenceBacked(key.SingleColumnType) &&
                !string.IsNullOrEmpty(mappingDatabase);
            var baseName = key.GeneratorBaseName;

            return(databaseSuffixRequired
        ? FormatKeyGeneratorName(mappingDatabase, baseName)
        : baseName);
        }
示例#9
0
        public void ValidateHierarchy(HierarchyDef hierarchyDef)
        {
            var keyFields = hierarchyDef.KeyFields;

            if (keyFields.Count == 0)
            {
                throw new DomainBuilderException(string.Format(
                                                     Strings.ExHierarchyXDoesntContainAnyKeyFields, hierarchyDef.Root.Name));
            }

            var root = hierarchyDef.Root;

            if (hierarchyDef.KeyGeneratorKind == KeyGeneratorKind.Default)
            {
                // Default key generator can't produce values with 2 or more fields
                if (keyFields.Count > 2)
                {
                    throw new DomainBuilderException(Strings.ExDefaultGeneratorCanServeHierarchyWithExactlyOneKeyField);
                }
                // if one of key fields is TypeId field and number of fields == 2 then it is OK
                if (keyFields.Count == 2 && keyFields.Find(f => f.Name == WellKnown.TypeIdFieldName) != null)
                {
                    throw new DomainBuilderException(Strings.ExDefaultGeneratorCanServeHierarchyWithExactlyOneKeyField);
                }
                var field = keyFields.FirstOrDefault(f => f.Name != WellKnown.TypeIdFieldName);
            }

            foreach (var keyField in keyFields)
            {
                if (keyField == null)
                {
                    throw new DomainBuilderException(String.Format(Strings.ExKeyStructureForXContainsNULLValue, root.Name));
                }

                FieldDef fieldDef = root.Fields[keyField.Name];
                if (fieldDef == null)
                {
                    throw new DomainBuilderException(string.Format(Strings.ExKeyFieldXXIsNotFound, root.Name, keyField.Name));
                }

                ValidateFieldType(root, fieldDef.ValueType, true);

                if (fieldDef.IsLazyLoad)
                {
                    throw new DomainBuilderException(string.Format(
                                                         Strings.ExFieldXCannotBeLazyLoadAsItIsIncludedInPrimaryKey, fieldDef.Name));
                }
            }
        }
示例#10
0
        public HierarchyDef DefineHierarchy(TypeDef typeDef)
        {
            // Prefer standard hierarchy definition flow
            var hra = typeDef.UnderlyingType.GetAttribute <HierarchyRootAttribute>(AttributeSearchOptions.Default);

            if (hra != null)
            {
                return(DefineHierarchy(typeDef, hra));
            }

            context.Validator.ValidateHierarchyRoot(context.ModelDef, typeDef);
            var result = new HierarchyDef(typeDef);

            return(result);
        }
        public HierarchyDef DefineHierarchy(TypeDef typeDef, HierarchyRootAttribute attribute)
        {
            context.Validator.ValidateHierarchyRoot(context.ModelDef, typeDef);

            var hierarchyDef = new HierarchyDef(typeDef);

            attributeProcessor.Process(hierarchyDef, attribute);

            // KeyGeneratorAttribute is optional
            var kga = typeDef.UnderlyingType.GetAttribute <KeyGeneratorAttribute>(AttributeSearchOptions.InheritAll);

            if (kga != null)
            {
                attributeProcessor.Process(hierarchyDef, kga);
            }

            return(hierarchyDef);
        }
示例#12
0
        public static void Inspect(BuildingContext context, HierarchyDef hierarchyDef)
        {
            var root = hierarchyDef.Root;

            BuildLog.Info(Strings.LogInspectingHierarchyX, root.Name);
            context.Validator.ValidateHierarchy(hierarchyDef);
            // Skip open generic hierarchies
            if (root.IsGenericTypeDefinition)
            {
                return;
            }

            // Check the presence of TypeId field
            FieldDef typeIdField;

            if (!root.Fields.TryGetValue(WellKnown.TypeIdFieldName, out typeIdField))
            {
                context.ModelInspectionResult.Actions.Enqueue(new AddTypeIdFieldAction(root));
            }
            else
            {
                context.ModelInspectionResult.Actions.Enqueue(new MarkFieldAsSystemAction(root, typeIdField));
            }

            // Should TypeId field be added to key fields?
            if (hierarchyDef.IncludeTypeId && hierarchyDef.KeyFields.Find(f => f.Name == WellKnown.TypeIdFieldName) == null)
            {
                context.ModelInspectionResult.Register(new AddTypeIdToKeyFieldsAction(hierarchyDef));
            }

            context.ModelInspectionResult.Actions.Enqueue(new ReorderFieldsAction(hierarchyDef));

            foreach (var keyField in hierarchyDef.KeyFields)
            {
                var field = root.Fields[keyField.Name];
                InspectField(context, root, field, true);
            }

            context.ModelInspectionResult.Actions.Enqueue(new AddPrimaryIndexAction(root));
        }
示例#13
0
        /// <summary>
        /// Builds base name for key generator.
        /// </summary>
        /// <param name="key">Key to build base key generator name for.</param>
        /// <param name="hierarchyDef">Hierarchy definition.</param>
        /// <returns>Base key generator name.</returns>
        public string BuildKeyGeneratorBaseName(KeyInfo key, HierarchyDef hierarchyDef)
        {
            if (key.GeneratorKind == KeyGeneratorKind.None)
            {
                throw new ArgumentOutOfRangeException("key.GeneratorKind");
            }

            if (!string.IsNullOrEmpty(hierarchyDef.KeyGeneratorName))
            {
                return(hierarchyDef.KeyGeneratorName);
            }

            if (key.GeneratorKind == KeyGeneratorKind.Custom)
            {
                throw new DomainBuilderException(string.Format(
                                                     Strings.ExKeyGeneratorAttributeOnTypeXRequiresNameToBeSet,
                                                     hierarchyDef.Root.UnderlyingType.GetShortName()));
            }

            // KeyGeneratorKind.Default:

            return(key.SingleColumnType.GetShortName());
        }
        // Constructors

        public CopyKeyFieldsAction(TypeDef target, HierarchyDef source)
            : base(target)
        {
            Source = source;
        }
示例#15
0
 internal void ValidateType(TypeDef typeDef, HierarchyDef hierarchyDef)
 {
 }
示例#16
0
 public void Process(HierarchyDef hierarchyDef, HierarchyRootAttribute attribute)
 {
     hierarchyDef.Schema        = attribute.InheritanceSchema;
     hierarchyDef.IncludeTypeId = attribute.IncludeTypeId;
     hierarchyDef.IsClustered   = attribute.Clustered;
 }
示例#17
0
        private static void InspectInterfaces(BuildingContext context)
        {
            foreach (var interfaceDef in context.ModelDef.Types.Where(t => t.IsInterface))
            {
                var interfaceNode = context.DependencyGraph.TryGetNode(interfaceDef);

                // Are there any dependencies at all?
                if (interfaceNode == null)
                {
                    context.ModelInspectionResult.Register(new RemoveTypeAction(interfaceDef));
                    continue;
                }

                // Are there any implementors?
                var implementorEdges = interfaceNode.IncomingEdges.Where(e => e.Kind == EdgeKind.Implementation).ToList();

                // There is no implementors. If there are no references to the interface, it could be safely removed
                if (implementorEdges.Count == 0 && interfaceNode.IncomingEdges.All(e => e.Kind != EdgeKind.Reference))
                {
                    context.ModelInspectionResult.Register(new RemoveTypeAction(interfaceDef));
                    continue;
                }

                HierarchyDef hierarchyDef;

                // There is only one implementor. Nothing else to do here
                if (implementorEdges.Count == 1)
                {
                    hierarchyDef = context.ModelDef.FindHierarchy(implementorEdges[0].Tail.Value);
                    if (hierarchyDef == null)
                    {
                        throw new DomainBuilderException(string.Format(
                                                             Strings.ExXImplementorsDontBelongToAnyHierarchy, interfaceDef.Name));
                    }

                    context.ModelInspectionResult.SingleHierarchyInterfaces.Add(interfaceDef);
                }
                else
                {
                    // Cleaning implementation edges. We need only direct implementors of interface
                    var directImplementorEdges = new HashSet <Edge <TypeDef> >();
                    foreach (var implementorEdge in implementorEdges)
                    {
                        if (context.ModelInspectionResult.RemovedTypes.Contains(implementorEdge.Tail.Value))
                        {
                            continue;
                        }

                        var implementorType = implementorEdge.Tail.Value.UnderlyingType;
                        var interfaceType   = implementorEdge.Head.Value.UnderlyingType;
                        // if not explicit implementation
                        var interfaceMap = implementorType.GetInterfaceMap(interfaceType);
                        if (!interfaceMap.TargetMethods.Any(tm => tm.DeclaringType == implementorType && tm.IsPrivate))
                        {
                            // Checking for ancestor-descendant connection
                            foreach (var directImplementorEdge in directImplementorEdges)
                            {
                                var directImplementorType = directImplementorEdge.Tail.Value.UnderlyingType;

                                // Implementor is a descendant of one of direct implementors
                                if (implementorType.IsSubclassOf(directImplementorType))
                                {
                                    interfaceNode.IncomingEdges.Remove(implementorEdge);
                                    implementorEdge.Tail.OutgoingEdges.Remove(implementorEdge);
                                    goto Next;
                                }

                                // Implementor is an ancestor of one of direct implementors
                                if (directImplementorType.IsSubclassOf(implementorType))
                                {
                                    directImplementorEdges.Remove(directImplementorEdge);
                                    directImplementorEdges.Add(implementorEdge);
                                    interfaceNode.IncomingEdges.Remove(directImplementorEdge);
                                    directImplementorEdge.Tail.OutgoingEdges.Remove(directImplementorEdge);
                                    goto Next;
                                }
                            }
                        }

                        // None of direct implementors is in the same hierarchy as implementor
                        directImplementorEdges.Add(implementorEdge);
                        Next :;
                    }

                    // Find hierarchies for all direct implementors
                    var hierarchies = new HashSet <HierarchyDef>();
                    foreach (var edge in directImplementorEdges)
                    {
                        var implementor = edge.Tail.Value;
                        var hierarchy   = context.ModelDef.FindHierarchy(implementor);
                        if (hierarchy != null)
                        {
                            hierarchies.Add(hierarchy);
                        }
                        else
                        {
                            context.ModelInspectionResult.Register(new RemoveTypeAction(implementor));
                        }
                    }

                    // TODO: what if hierarchies.Count == 0?
                    var count = hierarchies.Count;
                    if (count == 0)
                    {
                        throw new DomainBuilderException(string.Format(
                                                             Strings.ExXImplementorsDontBelongToAnyHierarchy, interfaceDef.Name));
                    }

                    if (count == 1)
                    {
                        context.ModelInspectionResult.SingleHierarchyInterfaces.Add(interfaceDef);
                    }
                    else
                    {
                        HierarchyDef master = null;
                        foreach (var candidate in hierarchies)
                        {
                            if (master == null)
                            {
                                master = candidate;
                                continue;
                            }

                            context.Validator.ValidateHierarchyEquality(interfaceDef, master, candidate);
                        }
                    }

                    hierarchyDef = hierarchies.First();
                }

                context.ModelInspectionResult.Register(new CopyKeyFieldsAction(interfaceDef, hierarchyDef));
                context.ModelInspectionResult.Register(new ReorderFieldsAction(interfaceDef, hierarchyDef));
                context.ModelInspectionResult.Register(new BuildImplementorListAction(interfaceDef));
                context.ModelInspectionResult.Register(new AddPrimaryIndexAction(interfaceDef));
            }
        }
示例#18
0
        // Constructors

        public ReorderFieldsAction(HierarchyDef hierarchy)
            : this(hierarchy.Root, hierarchy)
        {
        }
示例#19
0
        private KeyInfo BuildKeyInfo(TypeInfo root, HierarchyDef hierarchyDef)
        {
            var keyFields = root.Fields
                            .Where(field => field.IsPrimaryKey)
                            .OrderBy(field => field.MappingInfo.Offset)
                            .ToList();

            var keyColumns = keyFields
                             .Where(field => field.Column != null)
                             .Select(field => field.Column)
                             .ToList();

            var keyTupleDescriptor = TupleDescriptor.Create(
                keyColumns.Select(c => c.ValueType).ToArray(keyColumns.Count));
            var typeIdColumnIndex = -1;

            if (hierarchyDef.IncludeTypeId)
            {
                for (var i = 0; i < keyColumns.Count; i++)
                {
                    if (keyColumns[i].Field.IsTypeId)
                    {
                        typeIdColumnIndex = i;
                    }
                }
            }

            var key           = new KeyInfo(root.Name, keyFields, keyColumns, keyTupleDescriptor, typeIdColumnIndex);
            var generatorKind = hierarchyDef.KeyGeneratorKind;

            // Force absence of key generator if key is a reference.
            if (key.ContainsForeignKeys)
            {
                generatorKind = KeyGeneratorKind.None;
            }

            if (generatorKind == KeyGeneratorKind.Default)
            {
                var canBeHandled = key.SingleColumnType != null && KeyGeneratorFactory.IsSupported(key.SingleColumnType);
                // Force absence of key generator if key can not be handled by standard keygen.
                if (!canBeHandled)
                {
                    generatorKind = KeyGeneratorKind.None;
                }
            }

            if (generatorKind == KeyGeneratorKind.None)
            {
                // No key generator is attached.
                // Each hierarchy has it's own equality identifier.
                key.IsFirstAmongSimilarKeys = true;
                key.EqualityIdentifier      = new object();
                return(key);
            }

            // Hierarchy has key generator.

            // Setup key generator name.
            key.GeneratorKind     = generatorKind;
            key.GeneratorBaseName = context.NameBuilder.BuildKeyGeneratorBaseName(key, hierarchyDef);
            key.GeneratorName     = context.NameBuilder.BuildKeyGeneratorName(key, hierarchyDef);
            var generatorIdentity = context.Configuration.MultidatabaseKeys
        ? key.GeneratorBaseName
        : key.GeneratorName;

            // Equality identifier is the same if and only if key generator names match.
            key.IsFirstAmongSimilarKeys = !processedKeyGenerators.Contains(key.GeneratorName);
            if (key.IsFirstAmongSimilarKeys)
            {
                _ = processedKeyGenerators.Add(key.GeneratorName);
            }

            if (keyEqualityIdentifiers.TryGetValue(generatorIdentity, out var equalityIdentifier))
            {
                key.EqualityIdentifier = equalityIdentifier;
            }
            else
            {
                key.EqualityIdentifier = new object();
                keyEqualityIdentifiers.Add(generatorIdentity, key.EqualityIdentifier);
            }

            // Don't create sequences for user key generators
            // and for key generators that are not sequence-backed (such as GuidGenerator).
            if (key.GeneratorKind == KeyGeneratorKind.Custom || !IsSequenceBacked(key))
            {
                return(key);
            }

            // Generate backing sequence.
            if (sequences.TryGetValue(key.GeneratorName, out var sequence))
            {
                key.Sequence = sequence;
            }
            else
            {
                var newSequence = BuildSequence(hierarchyDef, key);
                if (context.Configuration.MultidatabaseKeys)
                {
                    EnsureSequenceSeedIsUnique(newSequence);
                }

                key.Sequence = newSequence;
                sequences.Add(key.GeneratorName, key.Sequence);
            }

            return(key);
        }
        // Constructors

        public AddTypeIdToKeyFieldsAction(HierarchyDef hierarchy)
            : base(hierarchy)
        {
        }
示例#21
0
 public ReorderFieldsAction(TypeDef target, HierarchyDef hierarchy)
     : base(hierarchy)
 {
     Target = target;
 }
 protected HierarchyAction(HierarchyDef hierarchy)
 {
     Hierarchy = hierarchy;
 }