You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			232 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //---------------------------------------------------------------------
 | |
| // <copyright file="EntityContainerRelationshipSet.cs" company="Microsoft">
 | |
| //      Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| //
 | |
| // @owner       Microsoft
 | |
| // @backupOwner Microsoft
 | |
| //---------------------------------------------------------------------
 | |
| 
 | |
| namespace System.Data.EntityModel.SchemaObjectModel
 | |
| {
 | |
|     using System.Collections.Generic;
 | |
|     using System.Data.Entity;
 | |
|     using System.Data.Metadata.Edm;
 | |
|     using System.Diagnostics;
 | |
|     using System.Xml;
 | |
| 
 | |
|     /// <summary>
 | |
|     /// Represents an RelationshipSet element.
 | |
|     /// </summary>
 | |
|     internal abstract class EntityContainerRelationshipSet : SchemaElement
 | |
|     {
 | |
| 
 | |
|         private IRelationship _relationship;
 | |
|         string _unresolvedRelationshipTypeName;
 | |
| 
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Constructs an EntityContainerRelationshipSet
 | |
|         /// </summary>
 | |
|         /// <param name="parentElement">Reference to the schema element.</param>
 | |
|         public EntityContainerRelationshipSet( EntityContainer parentElement )
 | |
|             : base( parentElement )
 | |
|         {
 | |
|         }
 | |
| 
 | |
|         public override string FQName
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return this.ParentElement.Name + "." + this.Name;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal IRelationship Relationship
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return _relationship;
 | |
|             }
 | |
|             set
 | |
|             {
 | |
|                 Debug.Assert(value != null, "relationship can never be set to null");
 | |
|                 _relationship = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         protected abstract bool HasEnd( string role );
 | |
|         protected abstract void AddEnd( IRelationshipEnd relationshipEnd, EntityContainerEntitySet entitySet );
 | |
|         internal abstract IEnumerable<EntityContainerRelationshipSetEnd> Ends { get; }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// The method that is called when an Association attribute is encountered.
 | |
|         /// </summary>
 | |
|         /// <param name="reader">An XmlReader positioned at the Association attribute.</param>
 | |
|         protected void HandleRelationshipTypeNameAttribute( XmlReader reader )
 | |
|         {
 | |
|             Debug.Assert( reader != null );
 | |
|             ReturnValue<string> value = HandleDottedNameAttribute( reader, _unresolvedRelationshipTypeName, Strings.PropertyTypeAlreadyDefined );
 | |
|             if ( value.Succeeded )
 | |
|             {
 | |
|                 _unresolvedRelationshipTypeName = value.Value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         
 | |
|         /// <summary>
 | |
|         /// Used during the resolve phase to resolve the type name to the object that represents that type
 | |
|         /// </summary>
 | |
|         internal override void ResolveTopLevelNames()
 | |
|         {
 | |
|             base.ResolveTopLevelNames();
 | |
| 
 | |
|             if ( _relationship == null )
 | |
|             {
 | |
|                 SchemaType element;
 | |
|                 if ( !Schema.ResolveTypeName( this, _unresolvedRelationshipTypeName, out element ) )
 | |
|                 {
 | |
|                     return;
 | |
|                 }
 | |
| 
 | |
|                 _relationship = element as IRelationship;
 | |
|                 if ( _relationship == null )
 | |
|                 {
 | |
|                     AddError( ErrorCode.InvalidPropertyType, EdmSchemaErrorSeverity.Error,
 | |
|                         System.Data.Entity.Strings.InvalidRelationshipSetType(element.Name ) );
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             foreach ( EntityContainerRelationshipSetEnd end in Ends )
 | |
|             {
 | |
|                 end.ResolveTopLevelNames();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal override void ResolveSecondLevelNames()
 | |
|         {
 | |
|             base.ResolveSecondLevelNames();
 | |
|             foreach (EntityContainerRelationshipSetEnd end in Ends)
 | |
|             {
 | |
|                 end.ResolveSecondLevelNames();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Do all validation for this element here, and delegate to all sub elements
 | |
|         /// </summary>
 | |
|         internal override void Validate()
 | |
|         {
 | |
|             base.Validate();
 | |
| 
 | |
|             InferEnds();
 | |
| 
 | |
|             // check out the ends
 | |
|             foreach ( EntityContainerRelationshipSetEnd end in Ends )
 | |
|             {
 | |
|                 end.Validate();
 | |
|             }
 | |
| 
 | |
| 
 | |
|             // Enabling Association between subtypes in case of Referential Constraints, since 
 | |
|             // CSD is blocked on this. We need to make a long term call about whether we should
 | |
|             // really allow this. Bug #520216
 | |
|             //foreach (ReferentialConstraint constraint in Relationship.Constraints)
 | |
|             //{
 | |
|             //    IRelationshipEnd dependentEnd = constraint.DependentRole.End;
 | |
|             //    EntityContainerRelationshipSetEnd setEnd = GetEnd(dependentEnd.Name);
 | |
|             //    Debug.Assert(setEnd != null);
 | |
|             //    //Make sure that the EntityType of the dependant role in a referential constraint
 | |
|             //    //covers the whole EntitySet( i.e. not  a subtype of the EntitySet's type).
 | |
|             //    if (!setEnd.EntitySet.EntityType.IsOfType(constraint.DependentRole.End.Type))
 | |
|             //    {
 | |
|             //        AddError(ErrorCode.InvalidDependentRoleType, EdmSchemaErrorSeverity.Error,
 | |
|             //            System.Data.Entity.Strings.InvalidDependentRoleType(dependentEnd.Type.FQName, dependentEnd.Name, 
 | |
|             //                                dependentEnd.Parent.FQName, setEnd.EntitySet.Name, setEnd.ParentElement.Name));
 | |
|             //    }
 | |
|             //}
 | |
| 
 | |
|             // Validate Number of ends is correct
 | |
|             //    What we know:
 | |
|             //      No ends are missing, becuase we infered all missing ends
 | |
|             //      No extra ends are there because the names have been matched, and an extra name will have caused an error
 | |
|             //
 | |
|             //    looks like no count validation needs to be done
 | |
| 
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Adds any ends that need to be infered
 | |
|         /// </summary>
 | |
|         private void InferEnds()
 | |
|         {
 | |
|             Debug.Assert( Relationship != null );
 | |
| 
 | |
|             foreach ( IRelationshipEnd relationshipEnd in Relationship.Ends )
 | |
|             {
 | |
|                 if ( ! HasEnd( relationshipEnd.Name ) )
 | |
|                 {
 | |
|                     EntityContainerEntitySet entitySet = InferEntitySet(relationshipEnd);
 | |
|                     if (entitySet != null)
 | |
|                     {
 | |
|                         // we don't have this end, we need to add it
 | |
|                         AddEnd(relationshipEnd, entitySet);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
|         /// <summary>
 | |
|         /// For the given relationship end, find the EntityContainer Property that will work for the extent
 | |
|         /// </summary>
 | |
|         /// <param name="relationshipEnd">The relationship end of the RelationshipSet that needs and extent</param>
 | |
|         /// <returns>Null is none could be found, or the EntityContainerProperty that is the valid extent</returns>
 | |
|         private EntityContainerEntitySet InferEntitySet( IRelationshipEnd relationshipEnd )
 | |
|         {
 | |
|             Debug.Assert(relationshipEnd != null, "relationshipEnd parameter is null");
 | |
| 
 | |
|             List<EntityContainerEntitySet> possibleExtents = new List<EntityContainerEntitySet>();
 | |
|             foreach ( EntityContainerEntitySet set in ParentElement.EntitySets )
 | |
|             {
 | |
|                 if ( relationshipEnd.Type.IsOfType( set.EntityType ) )
 | |
|                 {
 | |
|                     possibleExtents.Add( set );
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if ( possibleExtents.Count == 1 )
 | |
|             {
 | |
|                 return possibleExtents[0];
 | |
|             }
 | |
|             else if ( possibleExtents.Count == 0 )
 | |
|             {
 | |
|                 // no matchs
 | |
|                 AddError( ErrorCode.MissingExtentEntityContainerEnd, EdmSchemaErrorSeverity.Error,
 | |
|                     System.Data.Entity.Strings.MissingEntityContainerEnd(relationshipEnd.Name, FQName ) );
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // abmigous
 | |
|                 AddError( ErrorCode.AmbiguousEntityContainerEnd, EdmSchemaErrorSeverity.Error,
 | |
|                     System.Data.Entity.Strings.AmbiguousEntityContainerEnd(relationshipEnd.Name, FQName ) );
 | |
|             }
 | |
| 
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         
 | |
|         /// <summary>
 | |
|         /// The parent element as an EntityContainer
 | |
|         /// </summary>
 | |
|         internal new EntityContainer ParentElement
 | |
|         {
 | |
|             get
 | |
|             {
 | |
|                 return (EntityContainer)( base.ParentElement );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |