OneToOneMappingSerializer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntityDesign / Design / System / Data / Entity / Design / Common / OneToOneMappingSerializer.cs / 3 / OneToOneMappingSerializer.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Text;
using System.Data.Mapping;
using System.Data.Metadata.Edm;
using System.Reflection; 
using System.Diagnostics;
using System.Xml; 
using System.Data.Common.Utils; 
using System.Linq;
 
namespace System.Data.Entity.Design.Common
{
    internal static class OneToOneMappingSerializer
    { 
        internal class MappingLookups
        { 
            internal Dictionary StoreEntityTypeToModelEntityType = new Dictionary(); 
            internal Dictionary StoreEdmPropertyToModelEdmProperty = new Dictionary();
            internal Dictionary StoreEntitySetToModelEntitySet = new Dictionary(); 

            internal Dictionary StoreAssociationTypeToModelAssociationType = new Dictionary();
            internal Dictionary StoreAssociationEndMemberToModelAssociationEndMember = new Dictionary();
            internal Dictionary StoreAssociationSetToModelAssociationSet = new Dictionary(); 
            internal Dictionary StoreAssociationSetEndToModelAssociationSetEnd = new Dictionary();
 
            internal List CollapsedEntityAssociationSets = new List(); 
        }
 
        // this class represents a construct found in the ssdl where a link table
        // contained no data (all its properties were part of its keys)
        // it has exactly two associations
        // the entity type is the TO side of both associations 
        // all the colums are used as TO columns in the constraint
        internal class CollapsedEntityAssociationSet 
        { 
            private EntitySet _storeEntitySet;
            private List _storeAssociationSets = new List(2); 
            private AssociationSet _modelAssociationSet;

            public AssociationSet ModelAssociationSet
            { 
                get { return _modelAssociationSet; }
                set 
                { 
                    Debug.Assert(_modelAssociationSet == null, "why is this getting set multiple times, it should only be set after the new set is created");
                    _modelAssociationSet = value; 
                }
            }

            public CollapsedEntityAssociationSet(EntitySet entitySet) 
            {
                Debug.Assert(entitySet != null, "entitySet parameter is null"); 
                _storeEntitySet = entitySet; 
            }
 
            public EntitySet EntitySet
            {
                get { return _storeEntitySet; }
            } 

            public List AssociationSets 
            { 
                get { return _storeAssociationSets; }
            } 

            public void GetStoreAssociationSetEnd(int index, out AssociationSetEnd storeAssociationSetEnd, out RelationshipMultiplicity multiplicity, out OperationAction deleteBehavior)
            {
                Debug.Assert(index >= 0 && index < AssociationSets.Count, "out of bounds dude!!"); 
                Debug.Assert(AssociationSets.Count == 2, "This code depends on only having exactly two AssociationSets");
                GetFromAssociationSetEnd(AssociationSets[index], AssociationSets[(index+1)%2], out storeAssociationSetEnd, out multiplicity, out deleteBehavior); 
            } 

            private void GetFromAssociationSetEnd(AssociationSet definingSet, AssociationSet multiplicitySet, out AssociationSetEnd associationSetEnd, out RelationshipMultiplicity multiplicity, out OperationAction deleteBehavior) 
            {
                // for a situation like this (CD is CascadeDelete)
                //
                // --------  CD   --------  CD   -------- 
                // | A    |1 <-  1| AtoB |* <-  1|  B   |
                // |      |-------|      |-------|      | 
                // |      |       |      |       |      | 
                // --------       --------       --------
                // 
                // You get
                // --------  CD   --------
                // |  A   |* <-  1|  B   |
                // |      |-------|      | 
                // |      |       |      |
                // --------       -------- 
                // 
                // Notice that the of the new "link table association" muliplicities are opposite of what comming into the original link table
                // this seems counter intuitive at first, but makes sense when you think all the way through it 
                //
                // CascadeDelete Behavior (we can assume the runtime will always delete cascade
                //                         to the link table from the outside tables (it actually doesn't, but that is a bug))
                //  Store               Effective 
                //  A -> AToB <- B      None
                //  A <- AToB <- B      <- 
                //  A -> AToB -> B      -> 
                //  A <- AToB -> B      None
                //  A <- AToB    B      <- 
                //  A    AToB -> B      ->
                //  A -> AToB    B      None
                //  A    AToB <- B      None
                // 
                //  Other CascadeDelete rules
                //  1. Can't have a delete from a Many multiplicity end 
                //  2. Can't have a delete on both ends 
                //
 
                associationSetEnd = GetAssociationSetEnd(definingSet, true);
                AssociationSetEnd multiplicityAssociationSetEnd = GetAssociationSetEnd(multiplicitySet, false);
                multiplicity = multiplicityAssociationSetEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity;
                deleteBehavior = OperationAction.None; 
                if (multiplicity != RelationshipMultiplicity.Many)
                { 
                    OperationAction otherEndBehavior = GetAssociationSetEnd(definingSet, false).CorrespondingAssociationEndMember.DeleteBehavior; 
                    if(otherEndBehavior == OperationAction.None)
                    { 
                        // Since the other end does not have an operation
                        // that means that only one end could possibly have an operation, that is good
                        // so set it the operation
                        deleteBehavior = multiplicityAssociationSetEnd.CorrespondingAssociationEndMember.DeleteBehavior; 
                    }
                } 
            } 

            private static AssociationSetEnd GetAssociationSetEnd(AssociationSet set, bool fromEnd) 
            {
                Debug.Assert(set.ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[0]");
                ReferentialConstraint constraint = set.ElementType.ReferentialConstraints[0];
 
                Debug.Assert(set.AssociationSetEnds.Count == 2, "Associations are assumed to have two ends");
                int toEndIndex, fromEndIndex; 
                if (set.AssociationSetEnds[0].CorrespondingAssociationEndMember == constraint.FromRole) 
                {
                    fromEndIndex = 0; 
                    toEndIndex = 1;

                }
                else 
                {
                    fromEndIndex = 1; 
                    toEndIndex = 0; 
                }
 

                if (fromEnd)
                {
                    return set.AssociationSetEnds[fromEndIndex]; 
                }
                else 
                { 
                    return set.AssociationSetEnds[toEndIndex];
                } 
            }

            public bool MeetsRequirementsForCollapsableAssociation
            { 
                get
                { 
                    if (_storeAssociationSets.Count != 2) 
                        return false;
 
                    ReferentialConstraint constraint0;
                    ReferentialConstraint constraint1;
                    GetConstraints(out constraint0, out constraint1);
                    if (!IsEntityDependentSideOfBothAssociations(constraint0, constraint1)) 
                        return false;
 
                    if (!IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable(constraint0, constraint1)) 
                        return false;
 
                    if (!AreAllEntityColumnsMappedAsToColumns(constraint0, constraint1))
                        return false;

                    if (IsAtLeastOneColumnFKInBothAssociations(constraint0, constraint1)) 
                        return false;
 
                    return true; 
                }
            } 

            private bool IsAtLeastOneColumnFKInBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1)
            {
                return constraint1.ToProperties.Any(c => constraint0.ToProperties.Contains(c)); 
            }
 
            private bool IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            {
                return ToPropertyHasNonNullableColumn(constraint0) && ToPropertyHasNonNullableColumn(constraint1); 
            }

            private static bool ToPropertyHasNonNullableColumn(ReferentialConstraint constraint)
            { 
                foreach (EdmProperty property in constraint.ToProperties)
                { 
                    if (!property.Nullable) 
                    {
                        return true; 
                    }
                }
                return false;
            } 

            private bool AreAllEntityColumnsMappedAsToColumns(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            { 
                Set names = new Set();
                AddToPropertyNames(constraint0, names); 
                AddToPropertyNames(constraint1, names);
                return names.Count == _storeEntitySet.ElementType.Properties.Count;
            }
 
            private static void AddToPropertyNames(ReferentialConstraint constraint, Set names)
            { 
                foreach (EdmProperty property in constraint.ToProperties) 
                {
                    names.Add(property.Name); 
                }
            }

            private bool IsEntityDependentSideOfBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            {
                return ((RefType)constraint0.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType && ((RefType)constraint1.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType; 
            } 

            private void GetConstraints(out ReferentialConstraint constraint0, out ReferentialConstraint constraint1) 
            {
                Debug.Assert(_storeAssociationSets.Count == 2, "don't call this method if you don't have two associations");
                Debug.Assert(_storeAssociationSets[0].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[0]");
                Debug.Assert(_storeAssociationSets[1].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[1]"); 
                constraint0 = _storeAssociationSets[0].ElementType.ReferentialConstraints[0];
                constraint1 = _storeAssociationSets[1].ElementType.ReferentialConstraints[0]; 
            } 
        }
 
        public static void WriteXml(XmlWriter writer,
            MappingLookups lookups,
            EntityContainer storeContainer,
            EntityContainer modelContainer) 
        {
            EDesignUtil.CheckArgumentNull(writer, "writer"); 
            EDesignUtil.CheckArgumentNull(storeContainer, "storeContainer"); 
            EDesignUtil.CheckArgumentNull(modelContainer, "modelContainer");
 
            WriteMappingStartElement(writer);
            WriteEntityContainerMappingElement(writer, lookups, storeContainer, modelContainer );
            writer.WriteEndElement();
        } 

        private static void WriteEntityContainerMappingElement(XmlWriter writer, MappingLookups lookups, EntityContainer storeContainer, EntityContainer modelContainer) 
        { 
            writer.WriteStartElement(StorageMslConstructs.EntityContainerMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.StorageEntityContainerAttribute, storeContainer.Name); 
            writer.WriteAttributeString(StorageMslConstructs.CDMEntityContainerAttribute, modelContainer.Name);

            foreach (EntitySet set in lookups.StoreEntitySetToModelEntitySet.Keys)
            { 
                EntitySet modelEntitySet = lookups.StoreEntitySetToModelEntitySet[set];
                WriteEntitySetMappingElement(writer, lookups, set, modelEntitySet); 
            } 

            foreach(AssociationSet set in lookups.StoreAssociationSetToModelAssociationSet.Keys) 
            {
                AssociationSet modelAssociationSet = lookups.StoreAssociationSetToModelAssociationSet[set];
                WriteAssociationSetMappingElement(writer, lookups, set, modelAssociationSet);
            } 

            foreach (CollapsedEntityAssociationSet set in lookups.CollapsedEntityAssociationSets) 
            { 
                WriteAssociationSetMappingElement(writer, lookups, set);
            } 

            writer.WriteEndElement();
        }
 
        private static void WriteAssociationSetMappingElement(XmlWriter writer, MappingLookups lookups, CollapsedEntityAssociationSet collapsedAssociationSet)
        { 
            writer.WriteStartElement(StorageMslConstructs.AssociationSetMappingElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingNameAttribute, collapsedAssociationSet.ModelAssociationSet.Name);
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingTypeNameAttribute, collapsedAssociationSet.ModelAssociationSet.ElementType.FullName); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingStoreEntitySetAttribute, collapsedAssociationSet.EntitySet.Name);


            for (int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) 
            {
                AssociationSetEnd storeEnd; 
                RelationshipMultiplicity multiplicity; 
                OperationAction deleteBehavior;
                collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior); 
                AssociationSetEnd modelEnd = lookups.StoreAssociationSetEndToModelAssociationSetEnd[storeEnd];
                WriteEndPropertyElement(writer, lookups, storeEnd, modelEnd);
            }
 
            // don't need condition element
 
            writer.WriteEndElement(); 
        }
 
        private static void WriteAssociationSetMappingElement(XmlWriter writer, MappingLookups lookups, AssociationSet store, AssociationSet model)
        {
            writer.WriteStartElement(StorageMslConstructs.AssociationSetMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingNameAttribute, model.Name); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingTypeNameAttribute, model.ElementType.FullName);
 
            // all column names must be the primary key of the 
            // end, but as columns in the Fk table.
            AssociationSetEnd foreignKeyTableEnd = GetAssociationSetEndForForeignKeyTable(store); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingStoreEntitySetAttribute, foreignKeyTableEnd.EntitySet.Name);

            foreach (AssociationSetEnd storeEnd in store.AssociationSetEnds)
            { 
                AssociationSetEnd modelEnd = lookups.StoreAssociationSetEndToModelAssociationSetEnd[storeEnd];
                WriteEndPropertyElement(writer, lookups, storeEnd, modelEnd); 
            } 

            ReferentialConstraint constraint = GetReferentialConstraint(store); 
            foreach (EdmProperty fkColumn in constraint.ToProperties)
            {
                if (fkColumn.Nullable)
                { 
                    WriteConditionElement(writer, fkColumn);
                } 
            } 

            writer.WriteEndElement(); 
        }

        private static void WriteConditionElement(XmlWriter writer, EdmProperty fkColumn)
        { 
            writer.WriteStartElement(StorageMslConstructs.ConditionElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.ConditionColumnNameAttribute, fkColumn.Name); 
            writer.WriteAttributeString(StorageMslConstructs.ConditionIsNullAttribute, "false"); 
            writer.WriteEndElement();
        } 

        private static AssociationSetEnd GetAssociationSetEndForForeignKeyTable(AssociationSet store)
        {
            ReferentialConstraint constraint = GetReferentialConstraint(store); 
            return store.AssociationSetEnds.GetValue(constraint.ToRole.Name, false);
        } 
 
        internal static ReferentialConstraint GetReferentialConstraint(AssociationSet set)
        { 
            // this seeems like a hack, but it is what we have right now.
            ReferentialConstraint constraint = null;
            foreach (ReferentialConstraint rc in set.ElementType.ReferentialConstraints)
            { 
                Debug.Assert(constraint == null, "we should only get one");
                constraint = rc; 
            } 
            Debug.Assert(constraint != null, "we should get at least one constraint");
            return constraint; 
        }

        private static void WriteEndPropertyElement(XmlWriter writer, MappingLookups lookups, AssociationSetEnd store, AssociationSetEnd model)
        { 
            writer.WriteStartElement(StorageMslConstructs.EndPropertyMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.EndPropertyMappingNameAttribute, model.Name); 
            foreach (EdmProperty storeKeyMember in store.EntitySet.ElementType.KeyMembers) 
            {
                EdmProperty modelKeyMember = lookups.StoreEdmPropertyToModelEdmProperty[storeKeyMember]; 
                EdmProperty storeFkTableMember = GetAssociatedFkColumn(store, storeKeyMember);
                WriteScalarPropertyElement(writer, storeFkTableMember, modelKeyMember);
            }
            writer.WriteEndElement(); 
        }
 
        private static EdmProperty GetAssociatedFkColumn(AssociationSetEnd store, EdmProperty storeKeyProperty) 
        {
            ReferentialConstraint constraint = GetReferentialConstraint(store.ParentAssociationSet); 
            if (store.Name == constraint.FromRole.Name)
            {
                for (int i = 0; i < constraint.FromProperties.Count; i++)
                { 
                    if (constraint.FromProperties[i] == storeKeyProperty)
                    { 
                        // return the matching Fk column 
                        return constraint.ToProperties[i];
                    } 
                }
            }

                return storeKeyProperty; 
        }
 
        private static void WriteEntitySetMappingElement(XmlWriter writer, MappingLookups lookups, EntitySet store, EntitySet model) 
        {
            writer.WriteStartElement(StorageMslConstructs.EntitySetMappingElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingNameAttribute, model.Name);
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingStoreEntitySetAttribute, store.Name);
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingTypeNameAttribute, model.ElementType.FullName);
            foreach (EdmProperty storeProperty in store.ElementType.Properties) 
            {
                // we don't add the fk properties to c-space, so some are missing, 
                // check to see if we have a map for this one 
                if (lookups.StoreEdmPropertyToModelEdmProperty.ContainsKey(storeProperty))
                { 
                    EdmProperty modelProperty = lookups.StoreEdmPropertyToModelEdmProperty[storeProperty];
                    WriteScalarPropertyElement(writer, storeProperty, modelProperty);
                }
            } 
            writer.WriteEndElement();
        } 
 
        private static void WriteScalarPropertyElement(XmlWriter writer, EdmProperty store, EdmProperty model)
        { 
            Debug.Assert(store.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "only expect scalar type properties");
            Debug.Assert(model.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "only expect scalar type properties");

            writer.WriteStartElement(StorageMslConstructs.ScalarPropertyElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.ScalarPropertyNameAttribute, model.Name);
            writer.WriteAttributeString(StorageMslConstructs.ScalarPropertyColumnNameAttribute, store.Name); 
            writer.WriteEndElement(); 
        }
 
        private static void WriteMappingStartElement(XmlWriter writer)
        {
            writer.WriteStartElement(StorageMslConstructs.MappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.MappingSpaceAttribute, "C-S"); 
        }
 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Text;
using System.Data.Mapping;
using System.Data.Metadata.Edm;
using System.Reflection; 
using System.Diagnostics;
using System.Xml; 
using System.Data.Common.Utils; 
using System.Linq;
 
namespace System.Data.Entity.Design.Common
{
    internal static class OneToOneMappingSerializer
    { 
        internal class MappingLookups
        { 
            internal Dictionary StoreEntityTypeToModelEntityType = new Dictionary(); 
            internal Dictionary StoreEdmPropertyToModelEdmProperty = new Dictionary();
            internal Dictionary StoreEntitySetToModelEntitySet = new Dictionary(); 

            internal Dictionary StoreAssociationTypeToModelAssociationType = new Dictionary();
            internal Dictionary StoreAssociationEndMemberToModelAssociationEndMember = new Dictionary();
            internal Dictionary StoreAssociationSetToModelAssociationSet = new Dictionary(); 
            internal Dictionary StoreAssociationSetEndToModelAssociationSetEnd = new Dictionary();
 
            internal List CollapsedEntityAssociationSets = new List(); 
        }
 
        // this class represents a construct found in the ssdl where a link table
        // contained no data (all its properties were part of its keys)
        // it has exactly two associations
        // the entity type is the TO side of both associations 
        // all the colums are used as TO columns in the constraint
        internal class CollapsedEntityAssociationSet 
        { 
            private EntitySet _storeEntitySet;
            private List _storeAssociationSets = new List(2); 
            private AssociationSet _modelAssociationSet;

            public AssociationSet ModelAssociationSet
            { 
                get { return _modelAssociationSet; }
                set 
                { 
                    Debug.Assert(_modelAssociationSet == null, "why is this getting set multiple times, it should only be set after the new set is created");
                    _modelAssociationSet = value; 
                }
            }

            public CollapsedEntityAssociationSet(EntitySet entitySet) 
            {
                Debug.Assert(entitySet != null, "entitySet parameter is null"); 
                _storeEntitySet = entitySet; 
            }
 
            public EntitySet EntitySet
            {
                get { return _storeEntitySet; }
            } 

            public List AssociationSets 
            { 
                get { return _storeAssociationSets; }
            } 

            public void GetStoreAssociationSetEnd(int index, out AssociationSetEnd storeAssociationSetEnd, out RelationshipMultiplicity multiplicity, out OperationAction deleteBehavior)
            {
                Debug.Assert(index >= 0 && index < AssociationSets.Count, "out of bounds dude!!"); 
                Debug.Assert(AssociationSets.Count == 2, "This code depends on only having exactly two AssociationSets");
                GetFromAssociationSetEnd(AssociationSets[index], AssociationSets[(index+1)%2], out storeAssociationSetEnd, out multiplicity, out deleteBehavior); 
            } 

            private void GetFromAssociationSetEnd(AssociationSet definingSet, AssociationSet multiplicitySet, out AssociationSetEnd associationSetEnd, out RelationshipMultiplicity multiplicity, out OperationAction deleteBehavior) 
            {
                // for a situation like this (CD is CascadeDelete)
                //
                // --------  CD   --------  CD   -------- 
                // | A    |1 <-  1| AtoB |* <-  1|  B   |
                // |      |-------|      |-------|      | 
                // |      |       |      |       |      | 
                // --------       --------       --------
                // 
                // You get
                // --------  CD   --------
                // |  A   |* <-  1|  B   |
                // |      |-------|      | 
                // |      |       |      |
                // --------       -------- 
                // 
                // Notice that the of the new "link table association" muliplicities are opposite of what comming into the original link table
                // this seems counter intuitive at first, but makes sense when you think all the way through it 
                //
                // CascadeDelete Behavior (we can assume the runtime will always delete cascade
                //                         to the link table from the outside tables (it actually doesn't, but that is a bug))
                //  Store               Effective 
                //  A -> AToB <- B      None
                //  A <- AToB <- B      <- 
                //  A -> AToB -> B      -> 
                //  A <- AToB -> B      None
                //  A <- AToB    B      <- 
                //  A    AToB -> B      ->
                //  A -> AToB    B      None
                //  A    AToB <- B      None
                // 
                //  Other CascadeDelete rules
                //  1. Can't have a delete from a Many multiplicity end 
                //  2. Can't have a delete on both ends 
                //
 
                associationSetEnd = GetAssociationSetEnd(definingSet, true);
                AssociationSetEnd multiplicityAssociationSetEnd = GetAssociationSetEnd(multiplicitySet, false);
                multiplicity = multiplicityAssociationSetEnd.CorrespondingAssociationEndMember.RelationshipMultiplicity;
                deleteBehavior = OperationAction.None; 
                if (multiplicity != RelationshipMultiplicity.Many)
                { 
                    OperationAction otherEndBehavior = GetAssociationSetEnd(definingSet, false).CorrespondingAssociationEndMember.DeleteBehavior; 
                    if(otherEndBehavior == OperationAction.None)
                    { 
                        // Since the other end does not have an operation
                        // that means that only one end could possibly have an operation, that is good
                        // so set it the operation
                        deleteBehavior = multiplicityAssociationSetEnd.CorrespondingAssociationEndMember.DeleteBehavior; 
                    }
                } 
            } 

            private static AssociationSetEnd GetAssociationSetEnd(AssociationSet set, bool fromEnd) 
            {
                Debug.Assert(set.ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[0]");
                ReferentialConstraint constraint = set.ElementType.ReferentialConstraints[0];
 
                Debug.Assert(set.AssociationSetEnds.Count == 2, "Associations are assumed to have two ends");
                int toEndIndex, fromEndIndex; 
                if (set.AssociationSetEnds[0].CorrespondingAssociationEndMember == constraint.FromRole) 
                {
                    fromEndIndex = 0; 
                    toEndIndex = 1;

                }
                else 
                {
                    fromEndIndex = 1; 
                    toEndIndex = 0; 
                }
 

                if (fromEnd)
                {
                    return set.AssociationSetEnds[fromEndIndex]; 
                }
                else 
                { 
                    return set.AssociationSetEnds[toEndIndex];
                } 
            }

            public bool MeetsRequirementsForCollapsableAssociation
            { 
                get
                { 
                    if (_storeAssociationSets.Count != 2) 
                        return false;
 
                    ReferentialConstraint constraint0;
                    ReferentialConstraint constraint1;
                    GetConstraints(out constraint0, out constraint1);
                    if (!IsEntityDependentSideOfBothAssociations(constraint0, constraint1)) 
                        return false;
 
                    if (!IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable(constraint0, constraint1)) 
                        return false;
 
                    if (!AreAllEntityColumnsMappedAsToColumns(constraint0, constraint1))
                        return false;

                    if (IsAtLeastOneColumnFKInBothAssociations(constraint0, constraint1)) 
                        return false;
 
                    return true; 
                }
            } 

            private bool IsAtLeastOneColumnFKInBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1)
            {
                return constraint1.ToProperties.Any(c => constraint0.ToProperties.Contains(c)); 
            }
 
            private bool IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            {
                return ToPropertyHasNonNullableColumn(constraint0) && ToPropertyHasNonNullableColumn(constraint1); 
            }

            private static bool ToPropertyHasNonNullableColumn(ReferentialConstraint constraint)
            { 
                foreach (EdmProperty property in constraint.ToProperties)
                { 
                    if (!property.Nullable) 
                    {
                        return true; 
                    }
                }
                return false;
            } 

            private bool AreAllEntityColumnsMappedAsToColumns(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            { 
                Set names = new Set();
                AddToPropertyNames(constraint0, names); 
                AddToPropertyNames(constraint1, names);
                return names.Count == _storeEntitySet.ElementType.Properties.Count;
            }
 
            private static void AddToPropertyNames(ReferentialConstraint constraint, Set names)
            { 
                foreach (EdmProperty property in constraint.ToProperties) 
                {
                    names.Add(property.Name); 
                }
            }

            private bool IsEntityDependentSideOfBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1) 
            {
                return ((RefType)constraint0.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType && ((RefType)constraint1.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType; 
            } 

            private void GetConstraints(out ReferentialConstraint constraint0, out ReferentialConstraint constraint1) 
            {
                Debug.Assert(_storeAssociationSets.Count == 2, "don't call this method if you don't have two associations");
                Debug.Assert(_storeAssociationSets[0].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[0]");
                Debug.Assert(_storeAssociationSets[1].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[1]"); 
                constraint0 = _storeAssociationSets[0].ElementType.ReferentialConstraints[0];
                constraint1 = _storeAssociationSets[1].ElementType.ReferentialConstraints[0]; 
            } 
        }
 
        public static void WriteXml(XmlWriter writer,
            MappingLookups lookups,
            EntityContainer storeContainer,
            EntityContainer modelContainer) 
        {
            EDesignUtil.CheckArgumentNull(writer, "writer"); 
            EDesignUtil.CheckArgumentNull(storeContainer, "storeContainer"); 
            EDesignUtil.CheckArgumentNull(modelContainer, "modelContainer");
 
            WriteMappingStartElement(writer);
            WriteEntityContainerMappingElement(writer, lookups, storeContainer, modelContainer );
            writer.WriteEndElement();
        } 

        private static void WriteEntityContainerMappingElement(XmlWriter writer, MappingLookups lookups, EntityContainer storeContainer, EntityContainer modelContainer) 
        { 
            writer.WriteStartElement(StorageMslConstructs.EntityContainerMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.StorageEntityContainerAttribute, storeContainer.Name); 
            writer.WriteAttributeString(StorageMslConstructs.CDMEntityContainerAttribute, modelContainer.Name);

            foreach (EntitySet set in lookups.StoreEntitySetToModelEntitySet.Keys)
            { 
                EntitySet modelEntitySet = lookups.StoreEntitySetToModelEntitySet[set];
                WriteEntitySetMappingElement(writer, lookups, set, modelEntitySet); 
            } 

            foreach(AssociationSet set in lookups.StoreAssociationSetToModelAssociationSet.Keys) 
            {
                AssociationSet modelAssociationSet = lookups.StoreAssociationSetToModelAssociationSet[set];
                WriteAssociationSetMappingElement(writer, lookups, set, modelAssociationSet);
            } 

            foreach (CollapsedEntityAssociationSet set in lookups.CollapsedEntityAssociationSets) 
            { 
                WriteAssociationSetMappingElement(writer, lookups, set);
            } 

            writer.WriteEndElement();
        }
 
        private static void WriteAssociationSetMappingElement(XmlWriter writer, MappingLookups lookups, CollapsedEntityAssociationSet collapsedAssociationSet)
        { 
            writer.WriteStartElement(StorageMslConstructs.AssociationSetMappingElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingNameAttribute, collapsedAssociationSet.ModelAssociationSet.Name);
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingTypeNameAttribute, collapsedAssociationSet.ModelAssociationSet.ElementType.FullName); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingStoreEntitySetAttribute, collapsedAssociationSet.EntitySet.Name);


            for (int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) 
            {
                AssociationSetEnd storeEnd; 
                RelationshipMultiplicity multiplicity; 
                OperationAction deleteBehavior;
                collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior); 
                AssociationSetEnd modelEnd = lookups.StoreAssociationSetEndToModelAssociationSetEnd[storeEnd];
                WriteEndPropertyElement(writer, lookups, storeEnd, modelEnd);
            }
 
            // don't need condition element
 
            writer.WriteEndElement(); 
        }
 
        private static void WriteAssociationSetMappingElement(XmlWriter writer, MappingLookups lookups, AssociationSet store, AssociationSet model)
        {
            writer.WriteStartElement(StorageMslConstructs.AssociationSetMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingNameAttribute, model.Name); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingTypeNameAttribute, model.ElementType.FullName);
 
            // all column names must be the primary key of the 
            // end, but as columns in the Fk table.
            AssociationSetEnd foreignKeyTableEnd = GetAssociationSetEndForForeignKeyTable(store); 
            writer.WriteAttributeString(StorageMslConstructs.AssociationSetMappingStoreEntitySetAttribute, foreignKeyTableEnd.EntitySet.Name);

            foreach (AssociationSetEnd storeEnd in store.AssociationSetEnds)
            { 
                AssociationSetEnd modelEnd = lookups.StoreAssociationSetEndToModelAssociationSetEnd[storeEnd];
                WriteEndPropertyElement(writer, lookups, storeEnd, modelEnd); 
            } 

            ReferentialConstraint constraint = GetReferentialConstraint(store); 
            foreach (EdmProperty fkColumn in constraint.ToProperties)
            {
                if (fkColumn.Nullable)
                { 
                    WriteConditionElement(writer, fkColumn);
                } 
            } 

            writer.WriteEndElement(); 
        }

        private static void WriteConditionElement(XmlWriter writer, EdmProperty fkColumn)
        { 
            writer.WriteStartElement(StorageMslConstructs.ConditionElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.ConditionColumnNameAttribute, fkColumn.Name); 
            writer.WriteAttributeString(StorageMslConstructs.ConditionIsNullAttribute, "false"); 
            writer.WriteEndElement();
        } 

        private static AssociationSetEnd GetAssociationSetEndForForeignKeyTable(AssociationSet store)
        {
            ReferentialConstraint constraint = GetReferentialConstraint(store); 
            return store.AssociationSetEnds.GetValue(constraint.ToRole.Name, false);
        } 
 
        internal static ReferentialConstraint GetReferentialConstraint(AssociationSet set)
        { 
            // this seeems like a hack, but it is what we have right now.
            ReferentialConstraint constraint = null;
            foreach (ReferentialConstraint rc in set.ElementType.ReferentialConstraints)
            { 
                Debug.Assert(constraint == null, "we should only get one");
                constraint = rc; 
            } 
            Debug.Assert(constraint != null, "we should get at least one constraint");
            return constraint; 
        }

        private static void WriteEndPropertyElement(XmlWriter writer, MappingLookups lookups, AssociationSetEnd store, AssociationSetEnd model)
        { 
            writer.WriteStartElement(StorageMslConstructs.EndPropertyMappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.EndPropertyMappingNameAttribute, model.Name); 
            foreach (EdmProperty storeKeyMember in store.EntitySet.ElementType.KeyMembers) 
            {
                EdmProperty modelKeyMember = lookups.StoreEdmPropertyToModelEdmProperty[storeKeyMember]; 
                EdmProperty storeFkTableMember = GetAssociatedFkColumn(store, storeKeyMember);
                WriteScalarPropertyElement(writer, storeFkTableMember, modelKeyMember);
            }
            writer.WriteEndElement(); 
        }
 
        private static EdmProperty GetAssociatedFkColumn(AssociationSetEnd store, EdmProperty storeKeyProperty) 
        {
            ReferentialConstraint constraint = GetReferentialConstraint(store.ParentAssociationSet); 
            if (store.Name == constraint.FromRole.Name)
            {
                for (int i = 0; i < constraint.FromProperties.Count; i++)
                { 
                    if (constraint.FromProperties[i] == storeKeyProperty)
                    { 
                        // return the matching Fk column 
                        return constraint.ToProperties[i];
                    } 
                }
            }

                return storeKeyProperty; 
        }
 
        private static void WriteEntitySetMappingElement(XmlWriter writer, MappingLookups lookups, EntitySet store, EntitySet model) 
        {
            writer.WriteStartElement(StorageMslConstructs.EntitySetMappingElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingNameAttribute, model.Name);
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingStoreEntitySetAttribute, store.Name);
            writer.WriteAttributeString(StorageMslConstructs.EntitySetMappingTypeNameAttribute, model.ElementType.FullName);
            foreach (EdmProperty storeProperty in store.ElementType.Properties) 
            {
                // we don't add the fk properties to c-space, so some are missing, 
                // check to see if we have a map for this one 
                if (lookups.StoreEdmPropertyToModelEdmProperty.ContainsKey(storeProperty))
                { 
                    EdmProperty modelProperty = lookups.StoreEdmPropertyToModelEdmProperty[storeProperty];
                    WriteScalarPropertyElement(writer, storeProperty, modelProperty);
                }
            } 
            writer.WriteEndElement();
        } 
 
        private static void WriteScalarPropertyElement(XmlWriter writer, EdmProperty store, EdmProperty model)
        { 
            Debug.Assert(store.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "only expect scalar type properties");
            Debug.Assert(model.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType, "only expect scalar type properties");

            writer.WriteStartElement(StorageMslConstructs.ScalarPropertyElement, StorageMslConstructs.NamespaceURI); 
            writer.WriteAttributeString(StorageMslConstructs.ScalarPropertyNameAttribute, model.Name);
            writer.WriteAttributeString(StorageMslConstructs.ScalarPropertyColumnNameAttribute, store.Name); 
            writer.WriteEndElement(); 
        }
 
        private static void WriteMappingStartElement(XmlWriter writer)
        {
            writer.WriteStartElement(StorageMslConstructs.MappingElement, StorageMslConstructs.NamespaceURI);
            writer.WriteAttributeString(StorageMslConstructs.MappingSpaceAttribute, "C-S"); 
        }
 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK