Ejemplo n.º 1
0
        private GenericTypeLookupGraph BuildGenericTypeResolutionGraph(EntityModelSchema model)
        {
            var graph = new GenericTypeLookupGraph();

            foreach (var unmappedBaseType in model.EntityTypes.Where(e => (e.Annotations.OfType <ObjectLayerOnlyAnnotation>().Any() || e.Annotations.OfType <GenericTypeAnnotation>().Any()) && e.BaseType == null))
            {
                var genericTypeAnnotation = unmappedBaseType.Annotations.OfType <GenericTypeAnnotation>().FirstOrDefault();
                if (genericTypeAnnotation == null)
                {
                    continue;
                }

                int count = genericTypeAnnotation.TypeParameters.Count;
                for (int i = 0; i < count; ++i)
                {
                    var lookups           = new Dictionary <EntityType, GenericArgument>();
                    var typeParameterName = genericTypeAnnotation.TypeParameters[i];
                    graph.Add(new GenericTypeParameter(unmappedBaseType, typeParameterName), lookups);

                    this.WalkChildren(graph, model, unmappedBaseType, typeParameterName, lookups);
                }
            }

            return(graph);
        }
Ejemplo n.º 2
0
        private MemberProperty ResolveProperty(GenericTypeLookupGraph graph, MemberProperty property, EntityType newOwner)
        {
            GenericPropertyTypeAnnotation propertyTypeAnnotation = property.Annotations.OfType <GenericPropertyTypeAnnotation>().FirstOrDefault();

            if (propertyTypeAnnotation != null)
            {
                // Have to find where the property type comes from
                var parameter = propertyTypeAnnotation.GenericTypeParameterName;

                EntityType oldOwner = null;
                for (oldOwner = newOwner.BaseType; oldOwner != null; oldOwner = oldOwner.BaseType)
                {
                    if (oldOwner.Properties.Contains(property))
                    {
                        break;
                    }
                }

                Dictionary <EntityType, GenericArgument> lookups = graph[new GenericTypeParameter(oldOwner, parameter)];
                GenericArgument genericArgument = null;

                EntityType resolvingType = null;
                for (resolvingType = newOwner; resolvingType != null && !lookups.TryGetValue(resolvingType, out genericArgument); resolvingType = resolvingType.BaseType)
                {
                }

                // Means we found a concrete generic argument for this property type.
                if (resolvingType != null)
                {
                    return(new MemberProperty(property.Name, genericArgument.DataType)
                    {
                        IsPrimaryKey = property.IsPrimaryKey
                    });
                }

                return(new MemberProperty(property.Name)
                {
                    IsPrimaryKey = property.IsPrimaryKey,

                    Annotations =
                    {
                        new GenericPropertyTypeAnnotation(parameter)
                    }
                });
            }

            return(new MemberProperty(property.Name, property.PropertyType)
            {
                IsPrimaryKey = property.IsPrimaryKey
            });
        }
Ejemplo n.º 3
0
        private void WalkChildren(GenericTypeLookupGraph graph, EntityModelSchema model, EntityType baseType, string typeParameterName, Dictionary <EntityType, GenericArgument> lookups)
        {
            foreach (var childType in model.EntityTypes.Where(e => e.BaseType == baseType))
            {
                var genericTypeAnnotation      = childType.Annotations.OfType <GenericTypeAnnotation>().FirstOrDefault();
                var genericArgumentsAnnotation = childType.Annotations.OfType <GenericArgumentsAnnotation>().FirstOrDefault();

                GenericArgument argument        = null;
                bool            argumentMissing = genericArgumentsAnnotation == null ||
                                                  (argument = genericArgumentsAnnotation.GenericArguments.SingleOrDefault(ga => ga.TypeParameterName == typeParameterName)) == null;
                if (argumentMissing)
                {
                    var exception = new TaupoArgumentException(
                        string.Format(
                            CultureInfo.InvariantCulture,
                            "Entity type {0} cannot derive from entity type {1} because {0} does not have a type parameter {2} specified by a {3}.",
                            childType.Name,
                            baseType.Name,
                            typeParameterName,
                            typeof(GenericTypeAnnotation).Name));

                    if (genericTypeAnnotation == null)
                    {
                        throw exception;
                    }

                    var childTypeParameterPosition = genericTypeAnnotation.TypeParameters.IndexOf(typeParameterName);

                    if (childTypeParameterPosition == -1)
                    {
                        throw exception;
                    }

                    var childLookups = new Dictionary <EntityType, GenericArgument>();
                    graph.Add(new GenericTypeParameter(childType, typeParameterName), childLookups);

                    this.WalkChildren(graph, model, childType, typeParameterName, childLookups);

                    // Merge the child lookups back into lookups
                    foreach (var kvp in childLookups)
                    {
                        lookups[kvp.Key] = kvp.Value;
                    }
                }
                else
                {
                    lookups[childType] = argument;
                }
            }
        }
Ejemplo n.º 4
0
        private void PushPropertiesToDerivedType(EntityModelSchema model, GenericTypeLookupGraph graph, EntityType unmappedBaseType, List <AssociationSet> oldAssociationSetsToRemove, EntityType derivedType, Dictionary <EntitySet, EntitySet> oldNewMap)
        {
            // Push primitive properties into derived classes.
            foreach (var property in unmappedBaseType.AllProperties)
            {
                var newProperty = this.ResolveProperty(graph, property, derivedType);
                derivedType.Properties.Add(newProperty);
            }

            // Push navigation properties into derived classes and add a new AssociationType.
            foreach (var navigationProperty in unmappedBaseType.AllNavigationProperties)
            {
                var oldAssociationType = navigationProperty.Association;
                var oldThisEnd         = navigationProperty.FromAssociationEnd;
                var oldOtherEnd        = navigationProperty.ToAssociationEnd;

                var associationTypeEndLookup = new Dictionary <AssociationEnd, AssociationEnd>();
                var thisEnd  = associationTypeEndLookup[oldThisEnd] = new AssociationEnd(derivedType.Name, derivedType, oldThisEnd.Multiplicity, oldThisEnd.DeleteBehavior);
                var otherEnd = associationTypeEndLookup[oldOtherEnd] = new AssociationEnd(oldOtherEnd.RoleName, oldOtherEnd.EntityType, oldOtherEnd.Multiplicity, oldOtherEnd.DeleteBehavior);

                // Assumes combination of the derived type name and the old association type name is unique.
                var associationType = new AssociationType(oldAssociationType.NamespaceName, derivedType.Name + "_" + oldAssociationType.Name)
                {
                    associationTypeEndLookup[oldThisEnd],
                    associationTypeEndLookup[oldOtherEnd]
                };

                if (oldAssociationType.ReferentialConstraint != null)
                {
                    associationType.ReferentialConstraint = new ReferentialConstraint()
                                                            .WithDependentProperties(associationTypeEndLookup[oldAssociationType.ReferentialConstraint.DependentAssociationEnd], oldAssociationType.ReferentialConstraint.DependentProperties.ToArray())
                                                            .ReferencesPrincipalProperties(associationTypeEndLookup[oldAssociationType.ReferentialConstraint.PrincipalAssociationEnd], oldAssociationType.ReferentialConstraint.PrincipalProperties.ToArray());
                }

                var newNavigationProperty = new NavigationProperty(navigationProperty.Name, associationType, thisEnd, otherEnd);
                derivedType.NavigationProperties.Add(newNavigationProperty);

                model.Add(associationType);

                // Update the association sets for this association type.
                var oldAssociationSets = model.EntityContainers.SelectMany(e => e.AssociationSets).Where(a => a.AssociationType == oldAssociationType).ToArray();
                foreach (var oldAssociationSet in oldAssociationSets)
                {
                    EntitySet firstEntitySet;
                    if (!oldNewMap.TryGetValue(oldAssociationSet.Ends[0].EntitySet, out firstEntitySet))
                    {
                        firstEntitySet = oldAssociationSet.Ends[0].EntitySet;
                    }

                    EntitySet secondEntitySet;
                    if (!oldNewMap.TryGetValue(oldAssociationSet.Ends[1].EntitySet, out secondEntitySet))
                    {
                        secondEntitySet = oldAssociationSet.Ends[1].EntitySet;
                    }

                    var associationSet = new AssociationSet(associationType.Name + "_" + oldAssociationSet.Name, associationType)
                    {
                        new AssociationSetEnd(associationTypeEndLookup[oldAssociationSet.Ends[0].AssociationEnd], firstEntitySet),
                        new AssociationSetEnd(associationTypeEndLookup[oldAssociationSet.Ends[1].AssociationEnd], secondEntitySet),
                    };

                    oldAssociationSet.Container.Add(associationSet);
                }

                // Can't remove these yet, because we have to wait until the original has been copied for all derived entity types.
                oldAssociationSetsToRemove.AddRange(oldAssociationSets);
            }
        }