/// <summary>
        /// Initializes a new instance of the <see cref="AggregateExtension" /> class using the supplied extension entity names.
        /// </summary>
        public AggregateExtension(DomainModel domainModel, AggregateExtensionDefinition aggregateExtensionDefinition)
        {
            _domainModel = domainModel;

            AggregateRootEntityName = aggregateExtensionDefinition.AggregateRootEntityName;
            ExtensionEntityNames    = aggregateExtensionDefinition.ExtensionEntityNames;
        }
Example #2
0
        internal Aggregate(DomainModel domainModel, AggregateDefinition aggregateDefinition)
        {
            DomainModel = domainModel;

            FullName = aggregateDefinition.AggregateRootEntityName;

            var memberEntityNames = new[]
            {
                aggregateDefinition.AggregateRootEntityName
            }
            .Concat(aggregateDefinition.AggregateEntityNames)
            .Distinct()
            .ToArray();

            Name = aggregateDefinition.AggregateRootEntityName.Name;
            MemberEntityNames = memberEntityNames;
        }
Example #3
0
        internal Association(DomainModel domainModel, AssociationDefinition associationDefinition)
        {
            if (associationDefinition.PrimaryEntityProperties.Length != associationDefinition.SecondaryEntityProperties.Length)
            {
                throw new Exception("The association definition is invalid because a different number of properties were provided for the primary and secondary ends of the association.");
            }

            _domainModel = domainModel;

            FullName = associationDefinition.FullName;

            var primaryEntityAssociationProperties = associationDefinition.PrimaryEntityProperties
                                                     .Select(x => new AssociationProperty(x))
                                                     .ToArray();

            // Identifying associations mean that the properties in the receiving entity must also be identifying
            if (associationDefinition.IsIdentifying)
            {
                // Coerce each secondary entity property definition to be identifying
                associationDefinition.SecondaryEntityProperties.ForEach(p => p.IsIdentifying = true);
            }

            var secondaryEntityAssociationProperties = associationDefinition.SecondaryEntityProperties
                                                       .Select(x => new AssociationProperty(x))
                                                       .ToArray();

            Cardinality = associationDefinition.Cardinality;

            PrimaryEntityFullName   = associationDefinition.PrimaryEntityFullName;
            SecondaryEntityFullName = associationDefinition.SecondaryEntityFullName;

            _primaryEntityAssociationProperties = new Lazy <AssociationProperty[]>(
                () =>
            {
                Entity primaryEntity;

                if (!_domainModel.EntityByFullName.TryGetValue(PrimaryEntityFullName, out primaryEntity))
                {
                    throw new Exception($"The primary entity '{PrimaryEntityFullName}' could not be found.");
                }

                primaryEntityAssociationProperties.ForEach(p => p.Entity = primaryEntity);

                return(primaryEntityAssociationProperties);
            });

            _secondaryEntityAssociationProperties = new Lazy <AssociationProperty[]>(
                () =>
            {
                Entity secondaryEntity;

                if (!_domainModel.EntityByFullName.TryGetValue(SecondaryEntityFullName, out secondaryEntity))
                {
                    throw new Exception($"The secondary entity '{SecondaryEntityFullName}' could not be found.");
                }

                secondaryEntityAssociationProperties.ForEach(p => p.Entity = secondaryEntity);

                return(secondaryEntityAssociationProperties);
            });

            IsIdentifying              = associationDefinition.IsIdentifying;
            IsRequired                 = associationDefinition.IsRequired;
            IsRequiredCollection       = associationDefinition.Cardinality == Cardinality.OneToOneOrMore;
            ConstraintByDatabaseEngine = associationDefinition.ConstraintNames;
        }
Example #4
0
 /// <summary>
 /// Constructor that takes a set of DomainModelDefinitions to initialize it values
 /// </summary>
 /// <param name="domainModelDefinitions"></param>
 public DomainModelBuilder(IEnumerable <DomainModelDefinitions> domainModelDefinitions)
 {
     _domainModel = new DomainModel();
     domainModelDefinitions.ForEach(x => _domainModel.AddDomainModelDefinitions(x));
 }
Example #5
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Entity"/> class with a name and a list of
        /// properties that are defined locally on the entity (and are not part of incoming associations).
        /// </summary>
        /// <param name="domainModel">The incoming <seealso cref="DomainModel"/></param>
        /// <param name="entityDefinition">The incoming <seealso cref="EntityDefinition"/></param>
        internal Entity(DomainModel domainModel, EntityDefinition entityDefinition)
        {
            DomainModel = domainModel;

            Schema = entityDefinition.Schema;
            Name   = entityDefinition.Name;

            TableNameByDatabaseEngine = new Dictionary <DatabaseEngine, string>(entityDefinition.TableNames);

            Description        = entityDefinition.Description?.Trim();
            IsAbstract         = entityDefinition.IsAbstract;
            IsDeprecated       = entityDefinition.IsDeprecated;
            DeprecationReasons = entityDefinition.DeprecationReasons;

            _locallyDefinedProperties = entityDefinition.LocallyDefinedProperties.Select(x => new EntityProperty(x))
                                        .ToList();

            _identifiers = entityDefinition.Identifiers.Select(x => new EntityIdentifier(x))
                           .ToReadOnlyList();

            // Assign entity references to the identifiers, properties
            _identifiers.ForEach(i => i.Entity = this);
            _locallyDefinedProperties.ForEach(p => p.Entity = this);

            _properties = new Lazy <IReadOnlyList <EntityProperty> >(
                () =>
            {
                // All properties, identifying ones first
                var properties =
                    IncomingAssociations.Where(a => a.IsIdentifying)
                    .SelectMany(x => x.ThisAssociationProperties.Cast <DomainPropertyBase>())
                    .Concat(_locallyDefinedProperties.Where(p => p.IsIdentifying))
                    .Concat(
                        IncomingAssociations.Where(a => !a.IsIdentifying)
                        .SelectMany(x => x.ThisAssociationProperties))
                    .Concat(_locallyDefinedProperties.Where(p => !p.IsIdentifying))
                    .ToList();

                var distinctProperties = properties
                                         .Distinct(ModelComparers.DomainPropertyNameOnly)
                                         .ToList()
                                         .AsReadOnly();

                // Return the distinct set of EntityProperty instances,
                // constructing new EntityProperty instances for the "winning" AssociationProperty
                var entityProperties = distinctProperties.Select(dp =>
                                                                 (dp as EntityProperty) ?? new EntityProperty(dp as AssociationProperty))
                                       .ToList();

                // Ensure back-references to the Entity are set
                entityProperties.ForEach(p => p.Entity = this);

                return(entityProperties);
            });

            _nonIdentifyingProperties = new Lazy <IReadOnlyList <EntityProperty> >(
                () =>
                Properties.Where(p => !p.IsIdentifying)
                .ToList()
                .AsReadOnly());

            _derivedEntities = new Lazy <Entity[]>(
                () =>
            {
                AssociationView[] associations;

                if (!DomainModel.AssociationViewsByEntityFullName.TryGetValue(FullName, out associations))
                {
                    return(new Entity[0]);
                }

                return(associations
                       .Where(x => x.AssociationType == AssociationViewType.ToDerived)
                       .Select(x => x.OtherEntity)
                       .ToArray());
            });

            _propertyByName = new Lazy <IReadOnlyDictionary <string, EntityProperty> >(
                () =>
                Properties.ToDictionary(x => x.PropertyName, x => x, StringComparer.InvariantCultureIgnoreCase));

            _primaryIdentifier = new Lazy <EntityIdentifier>(
                () =>
                _identifiers.SingleOrDefault(x => x.IsPrimary));

            _alternateIdentifiers = new Lazy <IReadOnlyList <EntityIdentifier> >(
                () =>
                _identifiers.Where(x => !x.IsPrimary)
                .ToList());

            _baseAssociation = new Lazy <AssociationView>(
                () =>
            {
                AssociationView[] associations;

                if (!DomainModel.AssociationViewsByEntityFullName.TryGetValue(FullName, out associations))
                {
                    return(null);
                }

                return(associations.SingleOrDefault(a => a.AssociationType == AssociationViewType.FromBase));
            });

            _isEntityExtension = new Lazy <bool>(
                () => EdFiStandardEntityAssociation != null);

            _extensions = new Lazy <Entity[]>(
                () =>
            {
                AssociationView[] associations;

                if (!DomainModel.AssociationViewsByEntityFullName.TryGetValue(FullName, out associations))
                {
                    return(new Entity[0]);
                }

                return(associations
                       .Where(x => x.AssociationType == AssociationViewType.ToExtension)
                       .Select(x => x.OtherEntity)
                       .ToArray());
            });

            _extensionAssociations = new Lazy <AssociationView[]>(
                () =>
            {
                AssociationView[] associations;

                if (!DomainModel.AssociationViewsByEntityFullName.TryGetValue(FullName, out associations))
                {
                    return(new AssociationView[0]);
                }

                return(associations
                       .Where(x => x.AssociationType == AssociationViewType.ToExtension)
                       .ToArray());
            });

            _aggregateExtensionOneToOnes = new Lazy <AssociationView[]>(
                () =>
            {
                return(NavigableOneToOnes.Where(a => a.ThisEntity.Schema != a.OtherEntity.Schema)
                       .ToArray());
            });

            _aggregateExtensionChildren = new Lazy <AssociationView[]>(
                () =>
            {
                return(NavigableChildren.Where(a => a.ThisEntity.Schema != a.OtherEntity.Schema)
                       .ToArray());
            });

            _edFiStandardEntity = new Lazy <Entity>(
                () =>
            {
                if (EdFiStandardEntityAssociation == null)
                {
                    return(null);
                }

                return(EdFiStandardEntityAssociation.OtherEntity);
            });

            _edFiStandardEntityAssociation = new Lazy <AssociationView>(
                () =>
                IncomingAssociations
                .SingleOrDefault(a => a.AssociationType == AssociationViewType.FromCore)
                );

            _childToAggregateRootIdentifierPropertyMappings =
                new Lazy <IReadOnlyList <PropertyMapping> >(() => BuildChildToAggregateRootPropertyMappings(this));
        }
Example #6
0
        internal AssociationView(DomainModel domainModel, Association association, bool isPrimaryEntity)
        {
            _domainModel     = domainModel;
            Association      = association;
            _isPrimaryEntity = isPrimaryEntity;

            _thisProperties = new Lazy <EntityProperty[]>(
                () => _thisAssociationProperties.Value.Select(ap => ap.EntityProperty).ToArray());

            _otherProperties = new Lazy <EntityProperty[]>(
                () => _otherAssociationProperties.Value.Select(ap => ap.EntityProperty).ToArray());

            _thisAssociationProperties = new Lazy <AssociationProperty[]>(
                () =>
            {
                InitializeAssociationPropertyEntityBackReferences();

                return(_isPrimaryEntity
                        ? association.PrimaryEntityAssociationProperties
                        : association.SecondaryEntityAssociationProperties);
            });

            _otherAssociationProperties = new Lazy <AssociationProperty[]>(
                () =>
            {
                InitializeAssociationPropertyEntityBackReferences();

                return(_isPrimaryEntity
                        ? association.SecondaryEntityAssociationProperties
                        : association.PrimaryEntityAssociationProperties);
            });

            _propertyMappings = new Lazy <IReadOnlyList <PropertyMapping> >(
                () =>
                _thisProperties.Value.Select((p, i) => new PropertyMapping(p, _otherProperties.Value[i]))
                .ToList());

            _propertyMappingsByThisName = new Lazy <IReadOnlyDictionary <string, PropertyMapping> >(
                () =>
                new ReadOnlyDictionary <string, PropertyMapping>(
                    _propertyMappings.Value.ToDictionary(
                        m => m.ThisProperty.PropertyName,
                        m => m,
                        StringComparer.InvariantCultureIgnoreCase)));

            _propertyMappingsByOtherName = new Lazy <IReadOnlyDictionary <string, PropertyMapping> >(
                () =>
                new ReadOnlyDictionary <string, PropertyMapping>(
                    _propertyMappings.Value.ToDictionary(
                        m => m.OtherProperty.PropertyName,
                        m => m,
                        StringComparer.InvariantCultureIgnoreCase)));

            _foreignKeyNameParts = new Lazy <ForeignKeyNameParts>(
                () => GetForeignKeyNameParts(this));

            _isSoftDependency = new Lazy <bool>(
                () =>
            {
                // Navigable relationships do not span aggregates and do not represent aggregate dependencies
                if (IsNavigable)
                {
                    return(false);
                }

                bool isContainingEntityPresenceOptional = ThisEntity.AncestorsOrSelf.Select(e => e.ParentAssociation)
                                                          // Exclude root's ParentAssociation (which will be null)
                                                          .Where(av => av != null)
                                                          .Any(av =>
                                                               // An optional collection
                                                               (av.AssociationType == AssociationViewType.ManyToOne && !av.Association.IsRequiredCollection)

                                                               // An optional incoming one-to-one reference
                                                               || (av.AssociationType == AssociationViewType.OneToOneIncoming && !av.IsRequired));

                if (isContainingEntityPresenceOptional)
                {
                    return(true);
                }

                // Containing entity is required, so evaluate the reference itself
                if (AssociationType == AssociationViewType.ManyToOne ||
                    AssociationType == AssociationViewType.OneToOneIncoming)
                {
                    return(!IsRequired);
                }

                // All other associations do not represent dependencies
                return(false);
            });
        }