private void ValidateOnlyBaseEntitySetTypeDefinesConcurrency() { // collect all the base entitySet types Dictionary <SchemaEntityType, EntityContainerEntitySet> baseEntitySetTypes = new Dictionary <SchemaEntityType, EntityContainerEntitySet>(); foreach (SchemaElement element in Members) { EntityContainerEntitySet entitySet = element as EntityContainerEntitySet; if (entitySet != null && !baseEntitySetTypes.ContainsKey(entitySet.EntityType)) { baseEntitySetTypes.Add(entitySet.EntityType, entitySet); } } // look through each type in this schema and see if it is derived from a base // type if it is then see if it has some "new" Concurrency fields foreach (SchemaType type in Schema.SchemaTypes) { SchemaEntityType itemType = type as SchemaEntityType; if (itemType != null) { EntityContainerEntitySet set; if (TypeIsSubTypeOf(itemType, baseEntitySetTypes, out set) && TypeDefinesNewConcurrencyProperties(itemType)) { AddError(ErrorCode.ConcurrencyRedefinedOnSubTypeOfEntitySetType, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.ConcurrencyRedefinedOnSubTypeOfEntitySetType(itemType.FQName, set.EntityType.FQName, set.FQName)); } } } }
private void HandleEntitySetElement(XmlReader reader) { Debug.Assert(reader != null); EntityContainerEntitySet set = new EntityContainerEntitySet(this); set.Parse(reader); Members.Add(set, true, Strings.DuplicateEntityContainerMemberName); }
internal override SchemaElement Clone(SchemaElement parentElement) { EntityContainerEntitySet entitySet = new EntityContainerEntitySet((EntityContainer)parentElement); entitySet._definingQueryElement = this._definingQueryElement; entitySet._entityType = this._entityType; entitySet._schema = this._schema; entitySet._table = this._table; entitySet.Name = this.Name; return(entitySet); }
/// <summary> /// Adds a child EntitySet's tableKey (Schema/Table combination) to the validation collection /// This is used to validate that no child EntitySets share a Schema.Table combination /// </summary> private void CheckForDuplicateTableMapping(HashSet <string> tableKeys, EntityContainerEntitySet entitySet) { string schema; string table; if (String.IsNullOrEmpty(entitySet.DbSchema)) { // if there is no specified DbSchema, use the parent EntityContainer's name schema = this.Name; } else { schema = entitySet.DbSchema; } if (String.IsNullOrEmpty(entitySet.Table)) { // if there is no specified Table, use the EntitySet's name table = entitySet.Name; } else { table = entitySet.Table; } // create a key using the DbSchema and Table string tableKey = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}", schema, table); if (entitySet.DefiningQuery != null) { // don't consider the schema name for defining queries, because // we can't say for sure that it is the same as the entity container // so in this example // // <EntityContainer Name="dbo"> // <EntitySet Name="ByVal"> // <DefiningQuery>Select col1 from dbi.ByVal</DefiningQuery> // </EntitySet> // <EntitySet Name="ByVal1" Table="ByVal"/> // ... // // ByVal and ByVal1 should not conflict in our check tableKey = entitySet.Name; } bool alreadyExisted = !tableKeys.Add(tableKey); if (alreadyExisted) { entitySet.AddError(ErrorCode.AlreadyDefined, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.DuplicateEntitySetTable(entitySet.Name, schema, table)); } }
/// <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 (_entitySet == null) { _entitySet = this.ParentElement.ParentElement.FindEntitySet(_unresolvedEntitySetName); if (_entitySet == null) { AddError(ErrorCode.InvalidEndEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InvalidEntitySetNameReference(_unresolvedEntitySetName, Name)); } } }
/// <summary> /// Create and add a EntityContainerEnd from the IRelationshipEnd provided /// </summary> /// <param name="relationshipEnd">The relationship end of the end to add.</param> /// <param name="entitySet">The entitySet to associate with the relationship end.</param> protected override void AddEnd(IRelationshipEnd relationshipEnd, EntityContainerEntitySet entitySet) { Debug.Assert(relationshipEnd != null); Debug.Assert(!_relationshipEnds.ContainsKey(relationshipEnd.Name)); // we expect set to be null sometimes EntityContainerAssociationSetEnd end = new EntityContainerAssociationSetEnd(this); end.Role = relationshipEnd.Name; end.RelationshipEnd = relationshipEnd; end.EntitySet = entitySet; if (end.EntitySet != null) { _relationshipEnds.Add(end.Role, end); } }
/// <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> /// Do all validation for this element here, and delegate to all sub elements /// </summary> internal override void Validate() { // Now before we clone all the entity sets from the entity container that this entity container is extending, // we need to make sure that the entity container that is getting extended is already validated. since it might // be extending some other entity container, and we might want to populate this entity container, before // it gets extended if (!_isAlreadyValidated) { base.Validate(); // If this entity container extends some other entity container, then we should add all the // sets and function imports from that entity container to this entity container if (this.ExtendingEntityContainer != null) { // Call Validate on the entity container that is getting extended, so that its entity set // is populated this.ExtendingEntityContainer.Validate(); foreach (SchemaElement element in this.ExtendingEntityContainer.Members) { AddErrorKind error = this.Members.TryAdd(element.Clone(this)); DuplicateOrEquivalentMemberNameWhileExtendingEntityContainer(element, error); } } HashSet <string> tableKeys = new HashSet <string>(); foreach (SchemaElement element in Members) { EntityContainerEntitySet entitySet = element as EntityContainerEntitySet; if (entitySet != null && Schema.DataModel == SchemaDataModelOption.ProviderDataModel) { CheckForDuplicateTableMapping(tableKeys, entitySet); } element.Validate(); } ValidateRelationshipSetHaveUniqueEnds(); ValidateOnlyBaseEntitySetTypeDefinesConcurrency(); // Set isAlreadyValidated to true _isAlreadyValidated = true; } }
/// <summary> /// If the role name is missing but an entity set is given, figure out what the /// relationship end should be /// </summary> /// <param name="set">The given EntitySet</param> /// <returns>The appropriate relationship end</returns> private IRelationshipEnd InferRelationshipEnd(EntityContainerEntitySet set) { Debug.Assert(set != null, "set parameter is null"); if (ParentElement.Relationship == null) { return(null); } List <IRelationshipEnd> possibleEnds = new List <IRelationshipEnd>(); foreach (IRelationshipEnd end in ParentElement.Relationship.Ends) { if (set.EntityType.IsOfType(end.Type)) { possibleEnds.Add(end); } } if (possibleEnds.Count == 1) { return(possibleEnds[0]); } else if (possibleEnds.Count == 0) { // no matchs AddError(ErrorCode.FailedInference, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InferRelationshipEndFailedNoEntitySetMatch( set.Name, this.ParentElement.Name, ParentElement.Relationship.FQName, set.EntityType.FQName, this.ParentElement.ParentElement.FQName)); } else { // ambiguous AddError(ErrorCode.FailedInference, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InferRelationshipEndAmbiguous( set.Name, this.ParentElement.Name, ParentElement.Relationship.FQName, set.EntityType.FQName, this.ParentElement.ParentElement.FQName)); } return(null); }
/// <summary> /// Constructs an EntityContainerEntitySet /// </summary> /// <param name="parentElement">Reference to the schema element.</param> public EntityContainerEntitySetDefiningQuery(EntityContainerEntitySet parentElement) : base(parentElement) { }
/// <summary> /// validate the following negative scenarios: /// ReturnType="Collection(EntityTypeA)" /// ReturnType="Collection(EntityTypeA)" EntitySet="ESet.EType is not oftype EntityTypeA" /// EntitySet="A" /// ReturnType="Collection(ComplexTypeA)" EntitySet="something" /// ReturnType="Collection(ComplexTypeA)", but the ComplexTypeA has a nested complexType property, this scenario will be handle in the runtime /// </summary> private void ValidateFunctionImportReturnType(SchemaElement owner, SchemaType returnType, EntityContainerEntitySet entitySet, bool entitySetPathDefined) { // If entity type, verify specification of entity set and that the type is appropriate for the entity set SchemaEntityType entityType = returnType as SchemaEntityType; if (entitySet != null && entitySetPathDefined) { owner.AddError(ErrorCode.FunctionImportEntitySetAndEntitySetPathDeclared, EdmSchemaErrorSeverity.Error, Strings.FunctionImportEntitySetAndEntitySetPathDeclared(this.FQName)); } if (null != entityType) { // entity type if (null == entitySet) { // ReturnType="Collection(EntityTypeA)" owner.AddError(ErrorCode.FunctionImportReturnsEntitiesButDoesNotSpecifyEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportReturnEntitiesButDoesNotSpecifyEntitySet(this.FQName)); } else if (null != entitySet.EntityType && !entityType.IsOfType(entitySet.EntityType)) { // ReturnType="Collection(EntityTypeA)" EntitySet="ESet.EType is not oftype EntityTypeA" owner.AddError(ErrorCode.FunctionImportEntityTypeDoesNotMatchEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportEntityTypeDoesNotMatchEntitySet( this.FQName, entitySet.EntityType.FQName, entitySet.Name)); } } else { // complex type SchemaComplexType complexType = returnType as SchemaComplexType; if (complexType != null) { if (entitySet != null || entitySetPathDefined) { // ReturnType="Collection(ComplexTypeA)" EntitySet="something" owner.AddError( ErrorCode.ComplexTypeAsReturnTypeAndDefinedEntitySet, EdmSchemaErrorSeverity.Error, owner.LineNumber, owner.LinePosition, System.Data.Entity.Strings.ComplexTypeAsReturnTypeAndDefinedEntitySet(this.FQName, complexType.Name)); } } else { Debug.Assert(returnType == null || returnType is ScalarType || returnType is SchemaEnumType || returnType is Relationship, "null return type, scalar return type, enum return type or relationship expected here."); // scalar type or no return type if (entitySet != null || entitySetPathDefined) { // EntitySet="A" owner.AddError(ErrorCode.FunctionImportSpecifiesEntitySetButDoesNotReturnEntityType, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportSpecifiesEntitySetButNotEntityType(this.FQName)); } } } }
private static bool TypeIsSubTypeOf(SchemaEntityType itemType, Dictionary <SchemaEntityType, EntityContainerEntitySet> baseEntitySetTypes, out EntityContainerEntitySet set) { if (itemType.IsTypeHierarchyRoot) { // can't be a sub type if we are a base type set = null; return(false); } // walk up the hierarchy looking for a base that is the base type of an entityset for (SchemaEntityType baseType = itemType.BaseType as SchemaEntityType; baseType != null; baseType = baseType.BaseType as SchemaEntityType) { if (baseEntitySetTypes.ContainsKey(baseType)) { set = baseEntitySetTypes[baseType]; return(true); } } set = null; return(false); }
/// <summary> /// Constructs an EntityContainerEntitySet /// </summary> /// <param name="parentElement">Reference to the schema element.</param> public EntityContainerEntitySetDefiningQuery(EntityContainerEntitySet parentElement) : base(parentElement) { }
internal override SchemaElement Clone(SchemaElement parentElement) { EntityContainerEntitySet entitySet = new EntityContainerEntitySet((EntityContainer)parentElement); entitySet._definingQueryElement = this._definingQueryElement; entitySet._entityType = this._entityType; entitySet._schema = this._schema; entitySet._table = this._table; entitySet.Name = this.Name; return entitySet; }
private void ValidateFunctionImportReturnType(SchemaElement owner, SchemaType returnType, CollectionKind returnTypeCollectionKind, EntityContainerEntitySet entitySet, bool entitySetPathDefined) { if (returnType != null && !ReturnTypeMeetsFunctionImportBasicRequirements(returnType, returnTypeCollectionKind)) { owner.AddError(ErrorCode.FunctionImportUnsupportedReturnType, EdmSchemaErrorSeverity.Error, owner, GetReturnTypeErrorMessage(Schema.SchemaVersion, this.Name) ); } ValidateFunctionImportReturnType(owner, returnType, entitySet, entitySetPathDefined); }
private static bool TypeIsSubTypeOf(SchemaEntityType itemType, Dictionary<SchemaEntityType, EntityContainerEntitySet> baseEntitySetTypes, out EntityContainerEntitySet set) { if (itemType.IsTypeHierarchyRoot) { // can't be a sub type if we are a base type set = null; return false; } // walk up the hierarchy looking for a base that is the base type of an entityset for (SchemaEntityType baseType = itemType.BaseType as SchemaEntityType; baseType != null; baseType = baseType.BaseType as SchemaEntityType) { if (baseEntitySetTypes.ContainsKey(baseType)) { set = baseEntitySetTypes[baseType]; return true; } } set = null; return false; }
/// <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 ( _entitySet == null ) { _entitySet = this.ParentElement.ParentElement.FindEntitySet( _unresolvedEntitySetName ); if ( _entitySet == null ) { AddError( ErrorCode.InvalidEndEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InvalidEntitySetNameReference(_unresolvedEntitySetName, Name ) ); } } }
/// <summary> /// If the role name is missing but an entity set is given, figure out what the /// relationship end should be /// </summary> /// <param name="set">The given EntitySet</param> /// <returns>The appropriate relationship end</returns> private IRelationshipEnd InferRelationshipEnd( EntityContainerEntitySet set ) { Debug.Assert(set != null, "set parameter is null"); if ( ParentElement.Relationship == null ) { return null; } List<IRelationshipEnd> possibleEnds = new List<IRelationshipEnd>(); foreach ( IRelationshipEnd end in ParentElement.Relationship.Ends ) { if ( set.EntityType.IsOfType( end.Type ) ) { possibleEnds.Add( end ); } } if ( possibleEnds.Count == 1 ) { return possibleEnds[0]; } else if ( possibleEnds.Count == 0 ) { // no matchs AddError( ErrorCode.FailedInference, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InferRelationshipEndFailedNoEntitySetMatch( set.Name, this.ParentElement.Name, ParentElement.Relationship.FQName, set.EntityType.FQName, this.ParentElement.ParentElement.FQName ) ); } else { // ambiguous AddError( ErrorCode.FailedInference, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.InferRelationshipEndAmbiguous( set.Name, this.ParentElement.Name, ParentElement.Relationship.FQName, set.EntityType.FQName, this.ParentElement.ParentElement.FQName)); } return null; }
protected abstract void AddEnd( IRelationshipEnd relationshipEnd, EntityContainerEntitySet entitySet );
protected abstract void AddEnd(IRelationshipEnd relationshipEnd, EntityContainerEntitySet entitySet);
internal void ResolveEntitySet(SchemaElement owner, string unresolvedEntitySet, ref EntityContainerEntitySet entitySet) { Debug.Assert(IsFunctionImport, "Only FunctionImport elkements specify EntitySets"); Debug.Assert(null != _container, "function imports must know container"); // resolve entity set if (null == entitySet && null != unresolvedEntitySet) { entitySet = _container.FindEntitySet(unresolvedEntitySet); if (null == entitySet) { owner.AddError(ErrorCode.FunctionImportUnknownEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportUnknownEntitySet(unresolvedEntitySet, this.FQName)); } } }
private void ValidateFunctionImportReturnType(SchemaElement owner, SchemaType returnType, CollectionKind returnTypeCollectionKind, EntityContainerEntitySet entitySet, bool entitySetPathDefined) { if (returnType != null && !ReturnTypeMeetsFunctionImportBasicRequirements(returnType, returnTypeCollectionKind)) { owner.AddError(ErrorCode.FunctionImportUnsupportedReturnType, EdmSchemaErrorSeverity.Error, owner, GetReturnTypeErrorMessage(Schema.SchemaVersion, this.Name) ); } ValidateFunctionImportReturnType(owner, returnType, entitySet, entitySetPathDefined); }
/// <summary> /// validate the following negative scenarios: /// ReturnType="Collection(EntityTypeA)" /// ReturnType="Collection(EntityTypeA)" EntitySet="ESet.EType is not oftype EntityTypeA" /// EntitySet="A" /// ReturnType="Collection(ComplexTypeA)" EntitySet="something" /// ReturnType="Collection(ComplexTypeA)", but the ComplexTypeA has a nested complexType property, this scenario will be handle in the runtime /// </summary> private void ValidateFunctionImportReturnType(SchemaElement owner, SchemaType returnType, EntityContainerEntitySet entitySet, bool entitySetPathDefined) { // If entity type, verify specification of entity set and that the type is appropriate for the entity set SchemaEntityType entityType = returnType as SchemaEntityType; if (entitySet != null && entitySetPathDefined) { owner.AddError(ErrorCode.FunctionImportEntitySetAndEntitySetPathDeclared, EdmSchemaErrorSeverity.Error, Strings.FunctionImportEntitySetAndEntitySetPathDeclared(this.FQName)); } if (null != entityType) { // entity type if (null == entitySet) { // ReturnType="Collection(EntityTypeA)" owner.AddError(ErrorCode.FunctionImportReturnsEntitiesButDoesNotSpecifyEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportReturnEntitiesButDoesNotSpecifyEntitySet(this.FQName)); } else if (null != entitySet.EntityType && !entityType.IsOfType(entitySet.EntityType)) { // ReturnType="Collection(EntityTypeA)" EntitySet="ESet.EType is not oftype EntityTypeA" owner.AddError(ErrorCode.FunctionImportEntityTypeDoesNotMatchEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportEntityTypeDoesNotMatchEntitySet( this.FQName, entitySet.EntityType.FQName, entitySet.Name)); } } else { // complex type SchemaComplexType complexType = returnType as SchemaComplexType; if (complexType != null) { if (entitySet != null || entitySetPathDefined) { // ReturnType="Collection(ComplexTypeA)" EntitySet="something" owner.AddError( ErrorCode.ComplexTypeAsReturnTypeAndDefinedEntitySet, EdmSchemaErrorSeverity.Error, owner.LineNumber, owner.LinePosition, System.Data.Entity.Strings.ComplexTypeAsReturnTypeAndDefinedEntitySet(this.FQName, complexType.Name)); } } else { Debug.Assert(returnType == null || returnType is ScalarType || returnType is SchemaEnumType || returnType is Relationship, "null return type, scalar return type, enum return type or relationship expected here."); // scalar type or no return type if (entitySet != null || entitySetPathDefined) { // EntitySet="A" owner.AddError(ErrorCode.FunctionImportSpecifiesEntitySetButDoesNotReturnEntityType, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportSpecifiesEntitySetButNotEntityType(this.FQName)); } } } }
private void HandleEntitySetElement(XmlReader reader) { Debug.Assert(reader != null); EntityContainerEntitySet set = new EntityContainerEntitySet(this); set.Parse(reader); Members.Add(set, true, Strings.DuplicateEntityContainerMemberName); }
/// <summary> /// Create and add a EntityContainerEnd from the IRelationshipEnd provided /// </summary> /// <param name="relationshipEnd">The relationship end of the end to add.</param> /// <param name="entitySet">The entitySet to associate with the relationship end.</param> protected override void AddEnd(IRelationshipEnd relationshipEnd, EntityContainerEntitySet entitySet) { Debug.Assert(relationshipEnd != null); Debug.Assert(!_relationshipEnds.ContainsKey(relationshipEnd.Name)); // we expect set to be null sometimes var end = new EntityContainerAssociationSetEnd(this); end.Role = relationshipEnd.Name; end.RelationshipEnd = relationshipEnd; end.EntitySet = entitySet; if (end.EntitySet != null) { _relationshipEnds.Add(end.Role, end); } }
/// <summary> /// Adds a child EntitySet's tableKey (Schema/Table combination) to the validation collection /// This is used to validate that no child EntitySets share a Schema.Table combination /// </summary> private void CheckForDuplicateTableMapping(HashSet<string> tableKeys, EntityContainerEntitySet entitySet) { string schema; string table; if (String.IsNullOrEmpty(entitySet.DbSchema)) { // if there is no specified DbSchema, use the parent EntityContainer's name schema = this.Name; } else { schema = entitySet.DbSchema; } if (String.IsNullOrEmpty(entitySet.Table)) { // if there is no specified Table, use the EntitySet's name table = entitySet.Name; } else { table = entitySet.Table; } // create a key using the DbSchema and Table string tableKey = String.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}.{1}", schema, table); if (entitySet.DefiningQuery != null) { // don't consider the schema name for defining queries, because // we can't say for sure that it is the same as the entity container // so in this example // // <EntityContainer Name="dbo"> // <EntitySet Name="ByVal"> // <DefiningQuery>Select col1 from dbi.ByVal</DefiningQuery> // </EntitySet> // <EntitySet Name="ByVal1" Table="ByVal"/> // ... // // ByVal and ByVal1 should not conflict in our check tableKey = entitySet.Name; } bool alreadyExisted = !tableKeys.Add(tableKey); if (alreadyExisted) { entitySet.AddError(ErrorCode.AlreadyDefined, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.DuplicateEntitySetTable(entitySet.Name, schema, table)); } }
internal void ResolveEntitySet(SchemaElement owner, string unresolvedEntitySet, ref EntityContainerEntitySet entitySet) { Debug.Assert(IsFunctionImport, "Only FunctionImport elkements specify EntitySets"); Debug.Assert(null != _container, "function imports must know container"); // resolve entity set if (null == entitySet && null != unresolvedEntitySet) { entitySet = _container.FindEntitySet(unresolvedEntitySet); if (null == entitySet) { owner.AddError(ErrorCode.FunctionImportUnknownEntitySet, EdmSchemaErrorSeverity.Error, System.Data.Entity.Strings.FunctionImportUnknownEntitySet(unresolvedEntitySet, this.FQName)); } } }