Пример #1
0
        // <summary>
        //     Infer a Storage-layer EntityType name from a Conceptual-layer EntityType
        //     1. If this is a root type, then we will use the EntitySet name.
        //     2. If this is a derived type, then we will return the name of the EntitySet
        //     appended to the name of the EntityType.
        //     * NOTE: This is better than pluralization because this scales well for international users
        // </summary>
        internal static string GetStorageEntityTypeName(EntityType entityType, EdmItemCollection edm)
        {
            var storageEntityTypeName = String.Empty;

/*
 *          // First get the EntitySet name. Unfortunately the Metadata APIs don't have the ability to
 *          // get an EntitySet from an EntityType, so we have to incur this perf hit.
 *          var rootOrSelf = entityType.GetRootOrSelf();
 *          foreach (var entitySet in edm.GetAllEntitySets())
 *          {
 *              if (rootOrSelf == entitySet.ElementType)
 *              {
 *                  storageEntityTypeName = entitySet.Name;
 *              }
 *          }
 *
 *          Debug.Assert(!String.IsNullOrEmpty(storageEntityTypeName), "We didn't find an EntitySet for the EntityType " + entityType.Name);
 *
 *          if (entityType.IsDerivedType())
 *          {
 *              storageEntityTypeName = String.Format(CultureInfo.CurrentCulture, "{0}_{1}", storageEntityTypeName, entityType.Name);
 *          }
 */
            storageEntityTypeName = entityType.Name;

            storageEntityTypeName = GetTablePrefix(edm.GetNamespace()) + storageEntityTypeName;

            return(storageEntityTypeName);
        }
Пример #2
0
        internal static List <XElement> ConstructAssociationSetMappings(
            EdmItemCollection edm, string csdlNamespace, Version targetFrameworkVersion)
        {
            string prefix = OutputGeneratorHelpers.GetTablePrefix(edm.GetNamespace());
            var    associationSetMappings = new List <XElement>();

            foreach (var associationSet in edm.GetAllAssociationSets())
            {
                var association = associationSet.ElementType;

                if (association.IsManyToMany())
                {
                    var entityType1 = association.GetEnd1().GetEntityType();
                    var entityType2 = association.GetEnd2().GetEntityType();

                    var associationSetMapping = new XElement(
                        _msl + "AssociationSetMapping",
                        new XAttribute("Name", associationSet.Name),
                        new XAttribute("TypeName", csdlNamespace + "." + associationSet.ElementType.Name),
                        new XAttribute("StoreEntitySet", prefix + associationSet.Name));
                    var end1Property = new XElement(_msl + "EndProperty", new XAttribute("Name", association.GetEnd1().Name));
                    foreach (var property in entityType1.GetKeyProperties())
                    {
                        end1Property.Add(
                            new XElement(
                                _msl + "ScalarProperty", new XAttribute("Name", property.Name),
                                new XAttribute(
                                    "ColumnName", OutputGeneratorHelpers.GetFkNameM2M(association, association.GetEnd2(), property.Name))));
                    }
                    associationSetMapping.Add(end1Property);
                    var end2Property = new XElement(_msl + "EndProperty", new XAttribute("Name", association.GetEnd2().Name));
                    foreach (var property in entityType2.GetKeyProperties())
                    {
                        end2Property.Add(
                            new XElement(
                                _msl + "ScalarProperty", new XAttribute("Name", property.Name),
                                new XAttribute(
                                    "ColumnName", OutputGeneratorHelpers.GetFkNameM2M(association, association.GetEnd1(), property.Name))));
                    }
                    associationSetMapping.Add(end2Property);
                    associationSetMappings.Add(associationSetMapping);
                }
                else
                {
                    if (targetFrameworkVersion == EntityFrameworkVersion.Version1 ||
                        association.ReferentialConstraints.Count <= 0)
                    {
                        var dependentEnd = association.GetDependentEnd();
                        var principalEnd = association.GetOtherEnd(dependentEnd);
                        if (dependentEnd != null &&
                            principalEnd != null)
                        {
                            var dependentEntityType   = dependentEnd.GetEntityType();
                            var principalEntityType   = principalEnd.GetEntityType();
                            var associationSetMapping = new XElement(
                                _msl + "AssociationSetMapping",
                                new XAttribute("Name", associationSet.Name),
                                new XAttribute("TypeName", csdlNamespace + "." + associationSet.ElementType.Name),
                                new XAttribute("StoreEntitySet", OutputGeneratorHelpers.GetStorageEntityTypeName(dependentEntityType, edm)));
                            var end1Property = new XElement(_msl + "EndProperty", new XAttribute("Name", principalEnd.Name));
                            foreach (var property in principalEntityType.GetKeyProperties())
                            {
                                var columnName = (association.ReferentialConstraints.Count > 0)
                                                     ? property.GetDependentProperty(association.ReferentialConstraints.FirstOrDefault())
                                                 .Name
                                                     : OutputGeneratorHelpers.GetFkName(association, dependentEnd, property.Name);
                                end1Property.Add(
                                    new XElement(
                                        _msl + "ScalarProperty", new XAttribute("Name", property.Name),
                                        new XAttribute("ColumnName", columnName)));
                            }
                            associationSetMapping.Add(end1Property);
                            var end2Property = new XElement(_msl + "EndProperty", new XAttribute("Name", dependentEnd.Name));
                            foreach (var property in dependentEntityType.GetKeyProperties())
                            {
                                end2Property.Add(
                                    new XElement(
                                        _msl + "ScalarProperty", new XAttribute("Name", property.Name),
                                        new XAttribute("ColumnName", property.Name)));
                            }
                            associationSetMapping.Add(end2Property);

                            // All 0..1 ends of a non PK:PK association require an IsNull=false condition
                            if (dependentEnd.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne
                                &&
                                !association.IsPKToPK())
                            {
                                foreach (var key in dependentEntityType.GetKeyProperties())
                                {
                                    associationSetMapping.Add(
                                        new XElement(
                                            _msl + "Condition", new XAttribute("ColumnName", key.Name), new XAttribute("IsNull", "false")));
                                }
                            }

                            if (principalEnd.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)
                            {
                                foreach (var key in principalEntityType.GetKeyProperties())
                                {
                                    associationSetMapping.Add(
                                        new XElement(
                                            _msl + "Condition",
                                            new XAttribute(
                                                "ColumnName", OutputGeneratorHelpers.GetFkName(association, dependentEnd, key.Name)),
                                            new XAttribute("IsNull", "false")));
                                }
                            }
                            associationSetMappings.Add(associationSetMapping);
                        }
                    }
                }
            }
            return(associationSetMappings);
        }
Пример #3
0
        internal static List <XElement> ConstructAssociations(EdmItemCollection edm, string ssdlNamespace)
        {
            var associations = new List <XElement>();

            // Ignore *:* associations for now, just translate the CSDL Associations into SSDL Associations
            foreach (var association in edm.GetItems <AssociationType>().Where(a => !a.IsManyToMany()))
            {
                var associationElement = new XElement(_ssdl + "Association", new XAttribute("Name",
                                                                                            OutputGeneratorHelpers.GetTablePrefix(edm.GetNamespace()) + association.Name));

                var principalEnd = association.GetPrincipalEnd();
                var dependentEnd = association.GetDependentEnd();

                // 1. If we have a PK:PK relationship that has a ref constraint, then the multiplicity of the
                //      dependent end will always be 0..1.
                // 2. If we have a PK:PK relationship without a ref constraint, the multiplicity will
                //      always be *.
                // 3. If we have any other relationship, regardless of the ref constraint, we simply
                //      mirror the multiplicity from the C-side.
                if (principalEnd != null &&
                    dependentEnd != null)
                {
                    foreach (var end in association.AssociationEndMembers)
                    {
                        var entityType   = end.GetEntityType();
                        var multiplicity = TranslateMultiplicity(end.RelationshipMultiplicity);

                        if (end == dependentEnd &&
                            association.IsPKToPK())
                        {
                            multiplicity = (association.ReferentialConstraints.Count > 0)
                                               ? TranslateMultiplicity(RelationshipMultiplicity.ZeroOrOne)
                                               : TranslateMultiplicity(RelationshipMultiplicity.Many);
                        }

                        var associationEnd = new XElement(
                            _ssdl + "End",
                            new XAttribute("Role", end.Name),
                            new XAttribute("Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetStorageEntityTypeName(entityType, edm)),
                            new XAttribute("Multiplicity", multiplicity));

                        // Now we will attempt to add an OnDelete="Cascade" rule
                        if (end.GetOnDelete() == OperationAction.Cascade)
                        {
                            associationEnd.Add(
                                new XElement(
                                    _ssdl + "OnDelete",
                                    new XAttribute("Action", "Cascade")));
                        }

                        associationElement.Add(associationEnd);
                    }
                }

                // 1. If we have an existing ref constraint in the C-side, then we will simply mirror that in the SSDL.
                // 2. If we have a non *:* association without a ref constraint, then we specify the foreign keys' names of
                //      the dependent entity type (which is the principal entity type's keys' names)
                if (association.ReferentialConstraints.Count > 0)
                {
                    var refConstraint = association.ReferentialConstraints.FirstOrDefault();
                    if (refConstraint != null)
                    {
                        associationElement.Add(
                            ConstructReferentialConstraintInternal(
                                refConstraint.FromRole.Name,
                                refConstraint.FromProperties.Select(fp => fp.Name),
                                refConstraint.ToRole.Name,
                                refConstraint.ToProperties.Select(tp => tp.Name)));
                    }
                }
                else
                {
                    associationElement.Add(
                        ConstructReferentialConstraint(
                            principalEnd.Name,
                            principalEnd,
                            dependentEnd.Name,
                            dependentEnd));
                }

                OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(association, associationElement);

                associations.Add(associationElement);
            }

            // Now let's tackle the *:* Associations. A *:* conceptual Association means that there is actually a pair table
            // in the database, and two relationships -- one from the first end to the pair table and another from the pair table
            // to the second end.
            // For *:* associations, we'll also identify any extended properties and migrate them to _both_ associations on the S-side.
            foreach (var m2mAssoc in edm.GetItems <AssociationType>().Where(a => a.IsManyToMany()))
            {
                if (m2mAssoc.GetEnd1() != null &&
                    m2mAssoc.GetEnd2() != null)
                {
                    var entityType1 = m2mAssoc.GetEnd1().GetEntityType();
                    var entityType2 = m2mAssoc.GetEnd2().GetEntityType();
                    if (entityType1 != null &&
                        entityType2 != null)
                    {
                        var associationElement1 = new XElement(
                            _ssdl + "Association",
                            new XAttribute("Name", OutputGeneratorHelpers.GetStorageAssociationNameFromManyToMany(m2mAssoc.GetEnd1())));
                        associationElement1.Add(
                            new XElement(
                                _ssdl + "End",
                                new XAttribute("Role", m2mAssoc.GetEnd1().Name),
                                new XAttribute(
                                    "Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetStorageEntityTypeName(entityType1, edm)),
                                new XAttribute("Multiplicity", "1")));
                        associationElement1.Add(
                            new XElement(
                                _ssdl + "End",
                                new XAttribute("Role", m2mAssoc.Name),
                                new XAttribute("Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetTablePrefix(entityType1.NamespaceName) + m2mAssoc.Name),
                                new XAttribute("Multiplicity", "*")));
                        associationElement1.Add(
                            ConstructReferentialConstraint(m2mAssoc.GetEnd1().Name, m2mAssoc.GetEnd1(), m2mAssoc.Name, m2mAssoc.GetEnd2(), true));
                        OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(m2mAssoc, associationElement1);
                        associations.Add(associationElement1);

                        var associationElement2 = new XElement(
                            _ssdl + "Association",
                            new XAttribute("Name", OutputGeneratorHelpers.GetStorageAssociationNameFromManyToMany(m2mAssoc.GetEnd2())));
                        associationElement2.Add(
                            new XElement(
                                _ssdl + "End",
                                new XAttribute("Role", m2mAssoc.Name),
                                new XAttribute("Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetTablePrefix(entityType1.NamespaceName) + m2mAssoc.Name),
                                new XAttribute("Multiplicity", "*")));
                        associationElement2.Add(
                            new XElement(
                                _ssdl + "End",
                                new XAttribute("Role", m2mAssoc.GetEnd2().Name),
                                new XAttribute(
                                    "Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetStorageEntityTypeName(entityType2, edm)),
                                new XAttribute("Multiplicity", "1")));
                        associationElement2.Add(
                            ConstructReferentialConstraint(m2mAssoc.GetEnd2().Name, m2mAssoc.GetEnd2(), m2mAssoc.Name, m2mAssoc.GetEnd1(), true));
                        OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(m2mAssoc, associationElement2);
                        associations.Add(associationElement2);
                    }
                }
            }

            // Finally, we will add PK:PK Associations for any inheritance found in the conceptual. These will translate into PK constraints
            // in the DDL which will round-trip back in an identifiable way. Base Type's role in this association will have OnDelete action
            // set to Cascade so that if you delete a row from the base table, any corresponding rows in the child table will also be deleted.
            foreach (var derivedType in edm.GetAllEntityTypes().Where(et => et.BaseType != null))
            {
                var pkAssociation = new XElement(
                    _ssdl + "Association",
                    new XAttribute(
                        "Name",
                        String.Format(
                            CultureInfo.CurrentCulture, Resources.CodeViewFKConstraintDerivedType, OutputGeneratorHelpers.GetStorageEntityTypeName(derivedType, edm),
                            derivedType.BaseType.Name)));
                var baseTypeRole = new XElement(
                    _ssdl + "End",
                    new XAttribute("Role", derivedType.BaseType.Name),
                    new XAttribute(
                        "Type",
                        ssdlNamespace + "." + OutputGeneratorHelpers.GetStorageEntityTypeName(derivedType.BaseType as EntityType, edm)),
                    new XAttribute("Multiplicity", "1"));
                pkAssociation.Add(baseTypeRole);
                baseTypeRole.Add(new XElement(_ssdl + "OnDelete", new XAttribute("Action", "Cascade")));
                pkAssociation.Add(
                    new XElement(
                        _ssdl + "End",
                        new XAttribute("Role", derivedType.Name),
                        new XAttribute("Type", ssdlNamespace + "." + OutputGeneratorHelpers.GetStorageEntityTypeName(derivedType, edm)),
                        new XAttribute("Multiplicity", "0..1")));
                pkAssociation.Add(
                    ConstructReferentialConstraintInternal(
                        derivedType.BaseType.Name,
                        derivedType.GetRootOrSelf().GetKeyProperties().Select(k => k.Name),
                        derivedType.Name,
                        derivedType.GetRootOrSelf().GetKeyProperties().Select(k => k.Name)));
                associations.Add(pkAssociation);
            }

            return(associations);
        }