internal static XElement ConstructReferentialConstraint( string principalRole, AssociationEndMember principalEnd, string dependentRole, AssociationEndMember dependentEnd) { var refConstraintElement = new XElement(_ssdl + "ReferentialConstraint"); if (dependentEnd != null && principalEnd != null) { var dependentEntityType = dependentEnd.GetEntityType(); var principalEntityType = principalEnd.GetEntityType(); if (dependentEntityType != null && principalEntityType != null) { refConstraintElement = ConstructReferentialConstraintInternal( principalRole, principalEntityType.GetKeyProperties().Select(k => k.Name), dependentRole, principalEntityType.GetKeyProperties().Select( k => OutputGeneratorHelpers.GetFkName( dependentEnd.DeclaringType as AssociationType, dependentEnd, k.Name))); } } return(refConstraintElement); }
internal static XElement ConstructEntityContainerMapping(EdmItemCollection edm, string csdlNamespace) { var entityContainerMappingElement = new XElement( _msl + "EntityContainerMapping", new XAttribute("StorageEntityContainer", OutputGeneratorHelpers.ConstructStorageEntityContainerName(csdlNamespace)), new XAttribute("CdmEntityContainer", edm.GetEntityContainerName())); return(entityContainerMappingElement); }
// <summary> // A name derived from a *:* association will be: FK_[Association Name]_[End Name]. Note that we are // getting the association name for *one* of the SSDL associations that are inferred from a CSDL *:* // association. The 'principalEnd' corresponds to the end of the *:* association that will become // the principal end in the 1:* association (where the * end is the newly-constructed entity corresponding // to the link table) // </summary> internal static string GetStorageAssociationSetNameFromManyToMany(AssociationSet associationSet, AssociationEndMember principalEnd) { Debug.Assert(associationSet != null, "AssociationSet should not be null"); Debug.Assert(principalEnd != null, "The principal end cannot be null"); var associationSetName = String.Empty; if (associationSet != null && principalEnd != null) { associationSetName = String.Format( CultureInfo.CurrentCulture, Resources.CodeViewManyToManyAssocName, OutputGeneratorHelpers.GetTablePrefix(principalEnd.GetEntityType().NamespaceName) + associationSet.Name, principalEnd.Name); } return(associationSetName); }
// <summary> // A name derived from a *:* association will be: FK_[Association Name]_[End Name]. Note that we are // getting the association name for *one* of the SSDL associations that are inferred from a CSDL *:* // association. The 'principalEnd' corresponds to the end of the *:* association that will become // the principal end in the 1:* association (where the * end is the newly-constructed entity corresponding // to the link table) // </summary> internal static string GetStorageAssociationNameFromManyToMany(AssociationEndMember principalEnd) { var association = principalEnd.DeclaringType as AssociationType; Debug.Assert( association != null, "The DeclaringType of the AssociationEndMember " + principalEnd.Name + " should be an AssociationType"); Debug.Assert(principalEnd != null, "The principal end cannot be null"); var associationName = String.Empty; if (association != null && principalEnd != null) { associationName = String.Format( CultureInfo.CurrentCulture, Resources.CodeViewManyToManyAssocName, OutputGeneratorHelpers.GetTablePrefix(principalEnd.GetEntityType().NamespaceName) + association.Name, principalEnd.Name); } return(associationName); }
internal static List <XElement> ConstructEntitySetMappings(EdmItemCollection edm, string csdlNamespace) { var entitySetMappingElements = new List <XElement>(); foreach (var set in edm.GetAllEntitySets()) { var entitySetMapping = new XElement(_msl + "EntitySetMapping", new XAttribute("Name", set.Name)); foreach (var type in set.GetContainingTypes(edm)) { var entityTypeMapping = new XElement( _msl + "EntityTypeMapping", new XAttribute("TypeName", "IsTypeOf(" + type.FullName + ")")); var mappingFragment = new XElement( _msl + "MappingFragment", new XAttribute("StoreEntitySet", OutputGeneratorHelpers.GetStorageEntityTypeName(type, edm))); foreach (var property in type.GetRootOrSelf().GetKeyProperties()) { mappingFragment.Add( new XElement( _msl + "ScalarProperty", new XAttribute("Name", property.Name), new XAttribute("ColumnName", property.Name))); } foreach (var property in type.Properties.Except(type.GetKeyProperties()).Where(p => p.DeclaringType == type)) { if (property.IsComplexProperty()) { mappingFragment.Add(ConstructComplexProperty(property, property.Name, csdlNamespace)); } else { mappingFragment.Add( new XElement( _msl + "ScalarProperty", new XAttribute("Name", property.Name), new XAttribute("ColumnName", property.Name))); } } entityTypeMapping.Add(mappingFragment); entitySetMapping.Add(entityTypeMapping); } entitySetMappingElements.Add(entitySetMapping); } return(entitySetMappingElements); }
internal static XElement ConstructEntityContainer( EdmItemCollection edm, string databaseSchemaName, string csdlNamespace, string ssdlNamespace) { var entityContainerElement = new XElement( _ssdl + "EntityContainer", new XAttribute("Name", OutputGeneratorHelpers.ConstructStorageEntityContainerName(csdlNamespace))); #region Constructing EntitySets // In TPT, we need to create the SSDL EntitySets from the EntityTypes; we create another table for the derived type. foreach (var entityType in edm.GetAllEntityTypes()) { var entitySetElement = ConstructEntitySet( ssdlNamespace, OutputGeneratorHelpers.GetStorageEntityTypeName(entityType, edm), OutputGeneratorHelpers.GetStorageEntityTypeName(entityType, edm), "Tables", databaseSchemaName); // we would also tack on DefiningQueries here if we wanted entityContainerElement.Add(entitySetElement); } // Find all *:* Associations and create EntitySets in the SSDL foreach (var associationSet in edm.GetAllAssociationSets().Where(set => set.GetAssociation().IsManyToMany())) { var entitySetElement = ConstructEntitySet( ssdlNamespace, associationSet.Name, associationSet.ElementType.Name, "Tables", databaseSchemaName); entityContainerElement.Add(entitySetElement); } #endregion #region Constructing AssociationSets foreach (var associationSet in edm.GetAllAssociationSets()) { var assoc = associationSet.GetAssociation(); if (assoc.GetEnd1() != null && assoc.GetEnd2() != null) { // *:* C-Space associations: we will have two S-space associations bound to the pair table corresponding to each end if (assoc.IsManyToMany()) { // create an association from the first end to the pair table var associationSet1Element = ConstructAssociationSet( ssdlNamespace, OutputGeneratorHelpers.GetStorageAssociationSetNameFromManyToMany(associationSet, assoc.GetEnd1()), OutputGeneratorHelpers.GetStorageAssociationNameFromManyToMany(assoc.GetEnd1()), assoc.GetEnd1().Name, OutputGeneratorHelpers.GetStorageEntityTypeName(assoc.GetEnd1().GetEntityType(), edm), assoc.Name, associationSet.Name); // create an association from the second end to the pair table var associationSet2Element = ConstructAssociationSet( ssdlNamespace, OutputGeneratorHelpers.GetStorageAssociationSetNameFromManyToMany(associationSet, assoc.GetEnd2()), OutputGeneratorHelpers.GetStorageAssociationNameFromManyToMany(assoc.GetEnd2()), assoc.GetEnd2().Name, OutputGeneratorHelpers.GetStorageEntityTypeName(assoc.GetEnd2().GetEntityType(), edm), assoc.Name, associationSet.Name); entityContainerElement.Add(associationSet1Element); entityContainerElement.Add(associationSet2Element); } // All other associations: we essentially mirror the C-space associations else { var associationSetElement = ConstructAssociationSet( ssdlNamespace, associationSet.Name, assoc.Name, assoc.GetEnd1().Name, OutputGeneratorHelpers.GetStorageEntityTypeName(assoc.GetEnd1().GetEntityType(), edm), assoc.GetEnd2().Name, OutputGeneratorHelpers.GetStorageEntityTypeName(assoc.GetEnd2().GetEntityType(), edm)); entityContainerElement.Add(associationSetElement); } } } // Now we will construct AssociationSets with PK:PK associations based off of inheritance foreach (var derivedType in edm.GetAllEntityTypes().Where(et => et.BaseType != null)) { entityContainerElement.Add( ConstructAssociationSet( ssdlNamespace, String.Format( CultureInfo.CurrentCulture, Resources.CodeViewFKConstraintDerivedType, derivedType.Name, derivedType.BaseType.Name), String.Format( CultureInfo.CurrentCulture, Resources.CodeViewFKConstraintDerivedType, derivedType.Name, derivedType.BaseType.Name), derivedType.BaseType.Name, OutputGeneratorHelpers.GetStorageEntityTypeName(derivedType.BaseType as EntityType, edm), derivedType.Name, OutputGeneratorHelpers.GetStorageEntityTypeName(derivedType, edm))); } #endregion var csdlEntityContainer = edm.GetItems <EntityContainer>().FirstOrDefault(); Debug.Assert(csdlEntityContainer != null, "Could not find the CSDL EntityContainer to migrate extended properties"); if (csdlEntityContainer != null) { OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(csdlEntityContainer, entityContainerElement); } return(entityContainerElement); }
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", 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 + "." + m2mAssoc.Name), new XAttribute("Multiplicity", "*"))); associationElement1.Add( ConstructReferentialConstraint(m2mAssoc.GetEnd1().Name, m2mAssoc.GetEnd1(), m2mAssoc.Name, m2mAssoc.GetEnd2())); 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 + "." + 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())); 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, derivedType.Name, 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); }
internal static List <XElement> ConstructEntityTypes( EdmItemCollection edmItemCollection, DbProviderManifest providerManifest, Version targetVersion) { var entityTypes = new List <XElement>(); // Translate the CSDL EntityTypes into SSDL EntityTypes foreach (var csdlEntityType in edmItemCollection.GetAllEntityTypes()) { var entityTypeElement = new XElement( _ssdl + "EntityType", new XAttribute("Name", OutputGeneratorHelpers.GetStorageEntityTypeName(csdlEntityType, edmItemCollection))); // Add the keys if (csdlEntityType.GetRootOrSelf().GetKeyProperties().Any()) { var keyElement = new XElement(_ssdl + "Key"); foreach (EdmMember key in csdlEntityType.GetRootOrSelf().GetKeyProperties()) { keyElement.Add(new XElement(_ssdl + "PropertyRef", new XAttribute("Name", key.Name))); } entityTypeElement.Add(keyElement); } // Add only the properties on the declared type but also add the keys that might be on the root type foreach ( var property in csdlEntityType.Properties.Where(p => (p.DeclaringType == csdlEntityType)) .Union(csdlEntityType.GetRootOrSelf().GetKeyProperties())) { // If we encounter a ComplexType, we need to recursively flatten it out // into a list of all contained properties if (property.IsComplexProperty()) { property.VisitComplexProperty( (namePrefix, nestedProperty) => { var propertyElement = new XElement( _ssdl + "Property", new XAttribute("Name", namePrefix), new XAttribute("Type", nestedProperty.GetStoreType(providerManifest))); // Add StoreGeneratedPattern if it exists, but only add this to the table created from // the root type if (property.DeclaringType == csdlEntityType) { propertyElement.Add(ConstructStoreGeneratedPatternAttribute(nestedProperty, targetVersion)); } // Add the facets foreach (var facet in nestedProperty.InferSsdlFacetsForCsdlProperty(providerManifest)) { if (facet.Value != null) { propertyElement.Add(new XAttribute(facet.Name, facet.Value)); } } // We'll identify extended properties on all nested properties and migrate them. OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(nestedProperty, propertyElement); entityTypeElement.Add(propertyElement); }, "_", true); } else { var propertyElement = new XElement( _ssdl + "Property", new XAttribute("Name", property.Name), new XAttribute("Type", property.GetStoreType(providerManifest))); // Add StoreGeneratedPattern if it exists, but only add this to the table created from // the root type if (property.DeclaringType == csdlEntityType) { propertyElement.Add(ConstructStoreGeneratedPatternAttribute(property, targetVersion)); } // Add the facets foreach (var facet in property.InferSsdlFacetsForCsdlProperty(providerManifest)) { if (facet.Value != null) { var facetValue = facet.Value; // for DateTime attributes, if allow XAttribute to use its default formatting we end up // with attribute such as: // Facet="yyyy-MM-ddTHH:mm:ssZ", but we need Facet="yyyy-MM-dd HH:mm:ss.fffZ" (note the // space instead of 'T' and the fractions of seconds) to be valid SSDL if (typeof(DateTime).Equals(facetValue.GetType())) { facetValue = string.Format( CultureInfo.InvariantCulture, "{0:yyyy'-'MM'-'dd HH':'mm':'ss'.'fff'Z'}", facet.Value); } propertyElement.Add(new XAttribute(facet.Name, facetValue)); } } OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(property, propertyElement); entityTypeElement.Add(propertyElement); } } // 1. If there is a Referential Constraint specified on the C-side then there is no need // to create foreign keys since the dependent end's primary keys are the foreign keys. // 2. In other cases, we will have to infer the foreign keys by examining any associations that // the entity type participates in and add the principal keys as the foreign keys on the // dependent end. foreach (var containedAssociation in edmItemCollection.GetAllAssociations() .Where( a => (a.IsManyToMany() == false) && (a.ReferentialConstraints.Count == 0) && (a.GetDependentEnd().GetEntityType() == csdlEntityType))) { foreach (var keyProperty in containedAssociation.GetPrincipalEnd().GetEntityType().GetKeyProperties()) { var propertyElement = new XElement( _ssdl + "Property", new XAttribute( "Name", OutputGeneratorHelpers.GetFkName( containedAssociation, containedAssociation.GetDependentEnd(), keyProperty.Name)), new XAttribute("Type", keyProperty.GetStoreType(providerManifest))); // Add the facets foreach (var facet in keyProperty.InferSsdlFacetsForCsdlProperty(providerManifest)) { if (facet.Value != null && !facet.Name.Equals("Nullable", StringComparison.OrdinalIgnoreCase)) { propertyElement.Add(new XAttribute(facet.Name, facet.Value)); } } // The Nullability of this property is dependent on the multiplicity of the association. // If the principal end's multiplicity is 0..1, then this property is Nullable. propertyElement.Add( new XAttribute( "Nullable", containedAssociation.GetPrincipalEnd().RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)); entityTypeElement.Add(propertyElement); } } OutputGeneratorHelpers.CopyExtendedPropertiesToSsdlElement(csdlEntityType, entityTypeElement); entityTypes.Add(entityTypeElement); } // For all *:* Associations, we need a pair table and an associated pair EntityType foreach (var assoc in edmItemCollection.GetItems <AssociationType>().Where(a => a.IsManyToMany())) { var entityTypeElement = new XElement(_ssdl + "EntityType", new XAttribute("Name", assoc.Name)); // We determine the properties as the aggregation of the primary keys from both ends of the association. // These properties are also the keys of this new EntityTyp var keyElement = new XElement(_ssdl + "Key"); foreach (var key in assoc.GetEnd1().GetKeyProperties()) { keyElement.Add( new XElement( _ssdl + "PropertyRef", new XAttribute("Name", OutputGeneratorHelpers.GetFkName(assoc, assoc.GetEnd2(), key.Name)))); } foreach (var key in assoc.GetEnd2().GetKeyProperties()) { keyElement.Add( new XElement( _ssdl + "PropertyRef", new XAttribute("Name", OutputGeneratorHelpers.GetFkName(assoc, assoc.GetEnd1(), key.Name)))); } entityTypeElement.Add(keyElement); // These are foreign keys as well; we create 0..1 associations so these will be nullable keys foreach (var property in assoc.GetEnd1().GetKeyProperties()) { var propertyElement = new XElement( _ssdl + "Property", new XAttribute("Name", OutputGeneratorHelpers.GetFkName(assoc, assoc.GetEnd2(), property.Name)), new XAttribute("Type", property.GetStoreType(providerManifest))); // Add the facets foreach (var facet in property.InferSsdlFacetsForCsdlProperty(providerManifest)) { if (facet.Value != null) { propertyElement.Add(new XAttribute(facet.Name, facet.Value)); } } entityTypeElement.Add(propertyElement); } foreach (var property in assoc.GetEnd2().GetKeyProperties()) { var propertyElement = new XElement( _ssdl + "Property", new XAttribute("Name", OutputGeneratorHelpers.GetFkName(assoc, assoc.GetEnd1(), property.Name)), new XAttribute("Type", property.GetStoreType(providerManifest))); // Add the facets foreach (var facet in property.InferSsdlFacetsForCsdlProperty(providerManifest)) { if (facet.Value != null) { propertyElement.Add(new XAttribute(facet.Name, facet.Value)); } } entityTypeElement.Add(propertyElement); } entityTypes.Add(entityTypeElement); } return(entityTypes); }
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); }