private EntitySet CreateEntitySet( LoadMethodSessionState session, EntityType type ) { DbObjectKey key = session.GetKey(type); string schema = key.Schema; string table = null; if (key.TableName != type.Name) { table = key.TableName; } EntitySet entitySet = new EntitySet(type.Name, schema, table, null, type); MetadataProperty property = System.Data.EntityModel.SchemaObjectModel.SchemaElement.CreateMetadataPropertyFromOtherNamespaceXmlArtifact(DesignXmlConstants.EntityStoreSchemaGeneratorNamespace, DesignXmlConstants.EntityStoreSchemaGeneratorTypeAttributeName, GetSourceNameFromObjectType(key.ObjectType)); List<MetadataProperty> properties = new List<MetadataProperty>(); properties.Add(property); entitySet.AddMetadataProperties(properties); entitySet.SetReadOnly(); return entitySet; }
private AssociationSetEnd CreateModelAssociationSetEnd(LoadMethodSessionState session, AssociationSetEnd storeEnd, AssociationSet parentModelAssociationSet) { AssociationEndMember associationEnd = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[storeEnd.CorrespondingAssociationEndMember]; EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; string role = associationEnd.Name; AssociationSetEnd end = new AssociationSetEnd(entitySet, parentModelAssociationSet, associationEnd); return end; }
private KeyValuePair<string, RelationshipMultiplicity> CreateEndMultiplicityOverride(LoadMethodSessionState session, AssociationType storeAssociation, AssociationType modelAssociation) { // does the store have any constraints if (storeAssociation.ReferentialConstraints.Count == 0) { return new KeyValuePair<string, RelationshipMultiplicity>(); } ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0]; //For foreign key associations, having any nullable columns will imply 0..1 //multiplicity, while for independent associations, all columns must be non-nullable for //0..1 association. bool nullableColumnsImplyingOneToOneMultiplicity = false; if (this.GenerateForeignKeyProperties) { nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.All(p => p.Nullable == false); } else { nullableColumnsImplyingOneToOneMultiplicity = storeConstraint.ToProperties.Any(p => p.Nullable == false); } if (storeConstraint.FromRole.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne && storeConstraint.ToRole.RelationshipMultiplicity == RelationshipMultiplicity.Many && nullableColumnsImplyingOneToOneMultiplicity) { return new KeyValuePair<string, RelationshipMultiplicity>(storeConstraint.FromRole.Name, RelationshipMultiplicity.One); } return new KeyValuePair<string, RelationshipMultiplicity>(); }
private EntityType CreateModelEntityType(LoadMethodSessionState session, EntityType storeEntityType) { Debug.Assert(MetadataUtil.IsStoreType(storeEntityType), "this is not a store type"); Debug.Assert(storeEntityType.BaseType == null, "we are assuming simple generation from a database where no types will have a base type"); EntityType foundEntity; if (session.MappingLookups.StoreEntityTypeToModelEntityType.TryGetValue(storeEntityType, out foundEntity)) { // this entity type is used in two different entity sets return foundEntity; } // create all the properties List<EdmMember> members = new List<EdmMember>(); List<String> keyMemberNames = new List<string>(); UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false); string name = CreateModelName(this._pluralizationServiceHandler.GetEntityTypeName(storeEntityType.Name), session.UsedGlobalModelTypeNames); // Don't want to have a property with the same name as the entity type usedPropertyNames.RegisterUsedIdentifier(name); foreach (EdmProperty storeProperty in storeEntityType.Properties) { // add fk properties only if requested EdmMember member; bool isKey = storeEntityType.KeyMembers.TryGetValue(storeProperty.Name, false, out member); AssociationType association; if (isKey || this.GenerateForeignKeyProperties || !session.FkProperties.TryGetValue(storeProperty, out association)) { EdmProperty property = CreateModelProperty(session, storeProperty, usedPropertyNames); members.Add(property); if (isKey) { keyMemberNames.Add(property.Name); } } } var entityType = new EntityType(name, _namespaceName, DataSpace.CSpace, keyMemberNames, members); session.MappingLookups.StoreEntityTypeToModelEntityType.Add(storeEntityType, entityType); return entityType; }
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsedAssociationSet) { // create the association string associationName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedGlobalModelTypeNames); AssociationType association = new AssociationType(associationName, _namespaceName, false, DataSpace.CSpace); // create the association set string associationSetName = CreateModelName(collapsedAssociationSet.EntitySet.Name, session.UsedEntityContainerItemNames); AssociationSet set = new AssociationSet(associationSetName, association); // create the association and association set end members UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false); for(int i = 0; i < collapsedAssociationSet.AssociationSets.Count; i++) { AssociationSetEnd storeEnd; RelationshipMultiplicity multiplicity; OperationAction deleteBehavior; collapsedAssociationSet.GetStoreAssociationSetEnd(i, out storeEnd, out multiplicity, out deleteBehavior); AssociationEndMember end = CreateAssociationEndMember(session, storeEnd.CorrespondingAssociationEndMember, usedEndMemberNames, multiplicity, deleteBehavior); association.AddMember(end); EntitySet entitySet = session.MappingLookups.StoreEntitySetToModelEntitySet[storeEnd.EntitySet]; AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end); set.AddAssociationSetEnd(setEnd); session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, setEnd); } // don't need a referential constraint CreateModelNavigationProperties(session, association); collapsedAssociationSet.ModelAssociationSet = set; return set; }
private bool IsAssociationPartOfCandidateCollapsedAssociation(LoadMethodSessionState session, AssociationSet storeAssociationSet) { foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds) { if (session.CandidateCollapsedAssociations.ContainsKey(end.EntitySet)) { return true; } } return false; }
private void CollectAllFkProperties(LoadMethodSessionState session) { foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets) { if (storeSet.BuiltInTypeKind == BuiltInTypeKind.AssociationSet) { ReferentialConstraint constraint = OneToOneMappingSerializer.GetReferentialConstraint(((AssociationSet)storeSet)); foreach (EdmProperty property in constraint.ToProperties) { if (!session.FkProperties.ContainsKey(property)) { session.FkProperties.Add(property, ((AssociationSet)storeSet).ElementType); } } } } }
private bool TryGetEndEntities( LoadMethodSessionState session, RelationshipDetailsRow row, out EntityType pkEntityType, out EntityType fkEntityType) { RelationshipDetailsCollection table = row.Table; DbObjectKey pkKey = new DbObjectKey(row[table.PKCatalogColumn], row[table.PKSchemaColumn], row[table.PKTableColumn], DbObjectType.Unknown); DbObjectKey fkKey = new DbObjectKey(row[table.FKCatalogColumn], row[table.FKSchemaColumn], row[table.FKTableColumn], DbObjectType.Unknown); bool worked = session.TryGetEntity(pkKey, out pkEntityType); worked &= session.TryGetEntity(fkKey, out fkEntityType); return worked; }
private AssociationEndMember CreateAssociationEnd(LoadMethodSessionState session, EntityType type, RelationshipMultiplicity multiplicity, UniqueIdentifierService usedEndNames, OperationAction deleteAction ) { string role = usedEndNames.AdjustIdentifier(type.Name); RefType refType = type.GetReferenceType(); AssociationEndMember end = new AssociationEndMember(role, refType, multiplicity); end.DeleteBehavior = deleteAction; session.RelationshipEndTypeLookup.Add(end, type); return end; }
private void CreateAssociationTypes(LoadMethodSessionState session) { string currentRelationshipId = string.Empty; List<RelationshipDetailsRow> columns = new List<RelationshipDetailsRow>(); foreach (RelationshipDetailsRow row in _loader.LoadRelationships(session.Filters)) { string rowRelationshipId = row.RelationshipId; if (rowRelationshipId != currentRelationshipId) { if (!string.IsNullOrEmpty(currentRelationshipId)) { CreateAssociationType(session, columns); columns.Clear(); } currentRelationshipId = rowRelationshipId; } columns.Add(row); } if (!string.IsNullOrEmpty(currentRelationshipId)) { CreateAssociationType(session, columns); } }
private void CreateAssociationType(LoadMethodSessionState session, List<RelationshipDetailsRow> columns) { Debug.Assert(columns.Count != 0, "should have at least one column"); RelationshipDetailsRow firstRow = columns[0]; // get the entity types for the ends EntityType pkEntityType; EntityType fkEntityType; if (!TryGetEndEntities(session, firstRow, out pkEntityType, out fkEntityType)) { return; } if (!AreRelationshipColumnsTheTypesEntireKey(pkEntityType, columns, r => r.PKColumn)) { session.AddErrorsForType(pkEntityType, new EdmSchemaError(Strings.UnsupportedDbRelationship(firstRow.RelationshipName), (int)ModelBuilderErrorCode.UnsupportedDbRelationship, EdmSchemaErrorSeverity.Warning)); return; } UniqueIdentifierService usedEndNames = new UniqueIdentifierService(false); // figure out the lower bound of the pk end bool someFkColmnsAreNullable; if (_targetEntityFrameworkVersion == EntityFrameworkVersions.Version1) { someFkColmnsAreNullable = AreAllFkKeyColumnsNullable(fkEntityType, columns); } else { someFkColmnsAreNullable = AreAnyFkKeyColumnsNullable(fkEntityType, columns); } RelationshipMultiplicity pkMultiplicity = someFkColmnsAreNullable ? RelationshipMultiplicity.ZeroOrOne : RelationshipMultiplicity.One; //Get the Delete Action for the end and set it. //The only DeleteAction we support is Cascade, ignor all others for now. OperationAction onDeleteAction = OperationAction.None; if (firstRow.RelationshipIsCascadeDelete) { onDeleteAction = OperationAction.Cascade; } AssociationEndMember pkEnd = CreateAssociationEnd( session, pkEntityType, pkMultiplicity, usedEndNames, onDeleteAction); RelationshipMultiplicity fkMultiplicity = RelationshipMultiplicity.Many; if ( !someFkColmnsAreNullable && AreRelationshipColumnsTheTypesEntireKey(fkEntityType, columns, r => r.FKColumn)) { // both the pk and fk side columns are the keys of their types // so this is a 1 to one relationship fkMultiplicity = RelationshipMultiplicity.ZeroOrOne; } AssociationEndMember fkEnd = CreateAssociationEnd(session, fkEntityType, fkMultiplicity, usedEndNames, OperationAction.None); // create the type string typeName = session.UsedTypeNames.AdjustIdentifier(firstRow.RelationshipName); AssociationType type = new AssociationType(typeName, _namespaceName, false, DataSpace.SSpace); type.AddMember(pkEnd); type.AddMember(fkEnd); List<EdmSchemaError> errors = new List<EdmSchemaError>(); bool isValid = CreateReferentialConstraint(session, type, pkEnd, fkEnd, columns, errors); string errorMessage; // We can skip most validation checks if the FKs are directly surfaced (since we can produce valid mappings in these cases). if (!this.GenerateForeignKeyProperties) { if (IsFkPartiallyContainedInPK(type, out errorMessage)) { errors.Add(new EdmSchemaError( errorMessage, (int)ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Warning)); isValid = false; } if (isValid) { //Now check if any FK (which could also be a PK) is shared among multiple Associations (ie shared via foreign key constraint). // To do this we check if the Association Type being generated has any dependent property which is also a dependent in one of the association typed already added. //If so, we keep one Association and throw the rest away. foreach (var toPropertyOfAddedAssociation in session.AssociationTypes.SelectMany(t => t.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties))) { foreach (var toProperty in type.ReferentialConstraints.SelectMany(refconst => refconst.ToProperties)) { if (toProperty.DeclaringType.Equals(toPropertyOfAddedAssociation.DeclaringType) && toProperty.Equals(toPropertyOfAddedAssociation)) { errors.Add(new EdmSchemaError( Strings.SharedForeignKey(type.Name, toProperty, toProperty.DeclaringType), (int)ModelBuilderErrorCode.SharedForeignKey, EdmSchemaErrorSeverity.Warning)); isValid = false; break; } } if (!isValid) { break; } } } } if (isValid) { session.AssociationTypes.Add(type); } else { session.InvalidTypes.Add(type); session.RelationshipEndTypeLookup.Remove(pkEnd); session.RelationshipEndTypeLookup.Remove(fkEnd); } type.SetReadOnly(); session.AddErrorsForType(type, errors); }
private TypeUsage GetScalarFunctionTypeUsage(LoadMethodSessionState session, string dataType, out bool excludedForTarget) { PrimitiveType primitiveType; if (session.TryGetStorePrimitiveType(dataType, out primitiveType, out excludedForTarget)) { TypeUsage usage = TypeUsage.Create(primitiveType, FacetValues.NullFacetValues); return usage; } return null; }
private void CreateEdmFunction(LoadMethodSessionState session, DbObjectKey functionKey, List<FunctionDetailsReader.Memento> parameters) { Debug.Assert(parameters.Count != 0, "don't call the method with no data"); FunctionDetailsReader row = parameters[0].CreateReader(); FunctionParameter returnParameter = null; bool isValid = true; List<EdmSchemaError> errors = new List<EdmSchemaError>(); if (row.ReturnType != null) { Debug.Assert(!row.IsTvf, "TVF can't have ReturnType (used only for scalars)."); bool excludedForTarget; TypeUsage returnType = GetScalarFunctionTypeUsage(session, row.ReturnType, out excludedForTarget); if (returnType != null) { returnParameter = new FunctionParameter(EdmConstants.ReturnType, returnType, ParameterMode.ReturnValue); } else { isValid = false; errors.Add(new EdmSchemaError(excludedForTarget ? Strings.UnsupportedFunctionReturnDataTypeForTarget(row.ProcedureName, row.ReturnType) : Strings.UnsupportedFunctionReturnDataType(row.ProcedureName, row.ReturnType), (int)ModelBuilderErrorCode.UnsupportedType, EdmSchemaErrorSeverity.Warning)); } } else if (row.IsTvf) { if (_targetEntityFrameworkVersion < EntityFrameworkVersions.Version3) { return; } RowType tvfReturnType; if (session.TryGetTvfReturnType(functionKey, out tvfReturnType) && !session.InvalidTypes.Contains(tvfReturnType)) { var collectionType = tvfReturnType.GetCollectionType(); collectionType.SetReadOnly(); returnParameter = new FunctionParameter(EdmConstants.ReturnType, TypeUsage.Create(collectionType), ParameterMode.ReturnValue); } else { isValid = false; // If the TVF return type exists, but it is not valid, then reassign all its errors directly to the TVF. // This is needed in order to avoid the following kind of error reporting: // SSDL: // // <!-- Errors found while generating type: // column1 type not supported // column2 type not supported // <RowType /> // --> // ... // ... // <!-- Error found while generating type: // TableReferencedByTvfWasNotFound // <Function Name="TVF" .... /> // --> // // Instead we want something like this: // // <!-- Errors found while generating type: // column1 type not supported // column2 type not supported // TableReferencedByTvfWasNotFound // <Function Name="TVF" .... /> // --> // List<EdmSchemaError> tvfReturnTypeErrors; if (tvfReturnType != null && session.ItemToErrorsMap.TryGetValue(tvfReturnType, out tvfReturnTypeErrors)) { errors.AddRange(tvfReturnTypeErrors); session.ItemToErrorsMap.Remove(tvfReturnType); if (session.InvalidTypes.Contains(tvfReturnType)) { session.InvalidTypes.Remove(tvfReturnType); } } errors.Add(new EdmSchemaError( Strings.TableReferencedByTvfWasNotFound(functionKey), (int)ModelBuilderErrorCode.MissingTvfReturnTable, EdmSchemaErrorSeverity.Warning)); } } bool caseSensitive = false; UniqueIdentifierService uniqueIdentifiers = new UniqueIdentifierService(caseSensitive); List<FunctionParameter> functionParameters = new List<FunctionParameter>(); for (int i = 0; i < parameters.Count && !row.IsParameterNameNull; i++) { row.Attach(parameters[i]); TypeUsage parameterType = null; bool excludedForTarget = false; if (!row.IsParameterTypeNull) { parameterType = GetScalarFunctionTypeUsage(session, row.ParameterType, out excludedForTarget); } if (parameterType != null) { ParameterMode mode; if (!row.TryGetParameterMode(out mode)) { isValid = false; string modeValue = "null"; if (!row.IsParameterModeNull) { modeValue = row.ProcParameterMode; } errors.Add(new EdmSchemaError( Strings.ParameterDirectionNotValid( row.ProcedureName, row.ParameterName, modeValue), (int)ModelBuilderErrorCode.ParameterDirectionNotValid, EdmSchemaErrorSeverity.Warning)); } // the mode will get defaulted to something, so it is ok to keep creating after // an error getting the mode value. string parameterName = EntityModelSchemaGenerator.CreateValidEcmaName(row.ParameterName, 'p'); parameterName = uniqueIdentifiers.AdjustIdentifier(parameterName); FunctionParameter parameter = new FunctionParameter(parameterName, parameterType, mode); functionParameters.Add(parameter); } else { isValid = false; string typeValue = "null"; if (!row.IsParameterTypeNull) { typeValue = row.ParameterType; } errors.Add(new EdmSchemaError(excludedForTarget ? Strings.UnsupportedFunctionParameterDataTypeForTarget(row.ProcedureName, row.ParameterName, i, typeValue) : Strings.UnsupportedFunctionParameterDataType(row.ProcedureName, row.ParameterName, i, typeValue), (int)ModelBuilderErrorCode.UnsupportedType, EdmSchemaErrorSeverity.Warning)); } } string functionName = EntityModelSchemaGenerator.CreateValidEcmaName(row.ProcedureName, 'f'); functionName = session.UsedTypeNames.AdjustIdentifier(functionName); FunctionParameter[] returnParameters = returnParameter == null ? new FunctionParameter[0] : new FunctionParameter[] {returnParameter}; EdmFunction function = new EdmFunction(functionName, _namespaceName, DataSpace.SSpace, new EdmFunctionPayload { Schema = row.Schema, StoreFunctionName = functionName != row.ProcedureName ? row.ProcedureName : null, IsAggregate = row.IsIsAggregate, IsBuiltIn = row.IsBuiltIn, IsNiladic = row.IsNiladic, IsComposable = row.IsComposable, ReturnParameters = returnParameters, Parameters = functionParameters.ToArray() }); function.SetReadOnly(); session.AddErrorsForType(function, errors); if (isValid) { session.Functions.Add(function); } else { session.InvalidTypes.Add(function); } }
private void CreateEdmFunctions(LoadMethodSessionState session) { using(FunctionDetailsReader reader = _loader.LoadFunctionDetails(session.Filters)) { DbObjectKey currentFunction = new DbObjectKey(); List<FunctionDetailsReader.Memento> parameters = new List<FunctionDetailsReader.Memento>(); while(reader.Read()) { DbObjectKey rowFunction = reader.CreateDbObjectKey(); if (rowFunction != currentFunction) { if (!currentFunction.IsEmpty) { CreateEdmFunction(session, currentFunction, parameters); parameters.Clear(); } currentFunction = rowFunction; } parameters.Add(reader.CreateMemento()); } if (parameters.Count != 0) { CreateEdmFunction(session, currentFunction, parameters); } } }
private ComplexType CreateModelComplexTypeForTvfResult(LoadMethodSessionState session, string functionImportName, RowType tvfReturnType) { Debug.Assert(MetadataUtil.IsStoreType(tvfReturnType), "this is not a store type"); // create all the properties List<EdmMember> members = new List<EdmMember>(); UniqueIdentifierService usedPropertyNames = new UniqueIdentifierService(false); string name = CreateModelName(functionImportName + "_Result", session.UsedGlobalModelTypeNames); // Don't want to have a property with the same name as the complex type usedPropertyNames.RegisterUsedIdentifier(name); foreach (EdmProperty storeProperty in tvfReturnType.Properties) { EdmProperty property = CreateModelProperty(session, storeProperty, usedPropertyNames); members.Add(property); } var complexType = new ComplexType(name, _namespaceName, DataSpace.CSpace); foreach (var m in members) { complexType.AddMember(m); } return complexType; }
private bool CreateReferentialConstraint(LoadMethodSessionState session, AssociationType association, AssociationEndMember pkEnd, AssociationEndMember fkEnd, List<RelationshipDetailsRow> columns, List<EdmSchemaError> errors) { EdmProperty[] fromProperties = new EdmProperty[columns.Count]; EdmProperty[] toProperties = new EdmProperty[columns.Count]; EntityType pkEntityType = session.RelationshipEndTypeLookup[pkEnd]; EntityType fkEntityType = session.RelationshipEndTypeLookup[fkEnd]; for (int index = 0; index < columns.Count; index++) { EdmProperty property; if(!pkEntityType.Properties.TryGetValue(columns[index].PKColumn, false, out property)) { errors.Add( new EdmSchemaError( Strings.AssociationMissingKeyColumn( pkEntityType.Name, fkEntityType.Name, pkEntityType.Name + "." + columns[index].PKColumn), (int)ModelBuilderErrorCode.AssociationMissingKeyColumn, EdmSchemaErrorSeverity.Warning)); return false; } fromProperties[index] = property; if(!fkEntityType.Properties.TryGetValue(columns[index].FKColumn, false, out property)) { errors.Add( new EdmSchemaError( Strings.AssociationMissingKeyColumn( pkEntityType.Name, fkEntityType.Name, fkEntityType.Name + "." + columns[index].FKColumn), (int)ModelBuilderErrorCode.AssociationMissingKeyColumn, EdmSchemaErrorSeverity.Warning)); return false; } toProperties[index] = property; } ReferentialConstraint constraint = new ReferentialConstraint(pkEnd, fkEnd, fromProperties, toProperties); association.AddReferentialConstraint(constraint); return true; }
private IEnumerable<OneToOneMappingSerializer.CollapsedEntityAssociationSet> FindAllInvalidCollapsedAssociationCandidates(LoadMethodSessionState session) { Set<OneToOneMappingSerializer.CollapsedEntityAssociationSet> invalid = new Set<OneToOneMappingSerializer.CollapsedEntityAssociationSet>(); Dictionary<EntitySet, OneToOneMappingSerializer.CollapsedEntityAssociationSet> newCandidates = new Dictionary<EntitySet,OneToOneMappingSerializer.CollapsedEntityAssociationSet>(); foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.CandidateCollapsedAssociations.Values) { if (!collapsed.MeetsRequirementsForCollapsableAssociation) { invalid.Add(collapsed); } else { newCandidates.Add(collapsed.EntitySet, collapsed); } } foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in newCandidates.Values) { foreach (AssociationSet set in collapsed.AssociationSets) { EntitySet end0Set = set.AssociationSetEnds[0].EntitySet; EntitySet end1Set = set.AssociationSetEnds[1].EntitySet; // if both ends of the association are candidates throw both candidates out // because we can't collapse two entities out // and we don't know which entity we should collapse // so we won't collapse either if (newCandidates.ContainsKey(end0Set) && newCandidates.ContainsKey(end1Set)) { OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed0 = session.CandidateCollapsedAssociations[end0Set]; OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed1 = session.CandidateCollapsedAssociations[end1Set]; invalid.Add(collapsed0); invalid.Add(collapsed1); } } } return invalid; }
private void CreateModelNavigationProperties(LoadMethodSessionState session, AssociationType association) { Debug.Assert(association.Members.Count == 2, "this code assumes two ends"); AssociationEndMember end1 = (AssociationEndMember)association.Members[0]; AssociationEndMember end2 = (AssociationEndMember)association.Members[1]; CreateModelNavigationProperty(session, end1, end2); CreateModelNavigationProperty(session, end2, end1); }
private void SaveAssociationForCollapsedAssociationCandidate(LoadMethodSessionState session, AssociationSet storeAssociationSet) { foreach (AssociationSetEnd end in storeAssociationSet.AssociationSetEnds) { OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed; if (session.CandidateCollapsedAssociations.TryGetValue(end.EntitySet, out collapsed)) { collapsed.AssociationSets.Add(storeAssociationSet); } } }
private void CreateModelNavigationProperty(LoadMethodSessionState session, AssociationEndMember from, AssociationEndMember to) { EntityType entityType = (EntityType)((RefType)from.TypeUsage.EdmType).ElementType; UniqueIdentifierService usedMemberNames = new UniqueIdentifierService(false); LoadNameLookupWithUsedMemberNames(entityType, usedMemberNames); string name = CreateModelName(this._pluralizationServiceHandler.GetNavigationPropertyName(to, to.Name), usedMemberNames); NavigationProperty navigationProperty = new NavigationProperty(name, to.TypeUsage); navigationProperty.RelationshipType = (AssociationType)to.DeclaringType; navigationProperty.ToEndMember = to; navigationProperty.FromEndMember = from; entityType.AddMember(navigationProperty); }
private EntitySet CreateModelEntitySet(LoadMethodSessionState session, EntitySet storeEntitySet) { EntityType entity = CreateModelEntityType(session, storeEntitySet.ElementType); string name = CreateModelName(this._pluralizationServiceHandler.GetEntitySetName(storeEntitySet.Name), session.UsedEntityContainerItemNames); EntitySet set = new EntitySet(name, null, null, null, entity); session.MappingLookups.StoreEntitySetToModelEntitySet.Add(storeEntitySet, set); return set; }
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride, UniqueIdentifierService usedEndMemberNames) { RelationshipMultiplicity multiplicity = storeEndMember.RelationshipMultiplicity; if (endMultiplicityOverride.Key != null && endMultiplicityOverride.Key == storeEndMember.Name) { multiplicity = endMultiplicityOverride.Value; } return CreateAssociationEndMember(session, storeEndMember, usedEndMemberNames, multiplicity, storeEndMember.DeleteBehavior); }
private EdmProperty CreateModelProperty(LoadMethodSessionState session, EdmProperty storeProperty, UniqueIdentifierService usedPropertyNames) { string name = CreateModelName(storeProperty.Name, usedPropertyNames); TypeUsage cspaceTypeUsage = storeProperty.TypeUsage.GetModelTypeUsage(); EdmProperty property = new EdmProperty(name, cspaceTypeUsage); this.AddStoreGeneratedPatternAnnoation(property, storeProperty.TypeUsage); session.MappingLookups.StoreEdmPropertyToModelEdmProperty.Add(storeProperty, property); return property; }
private AssociationEndMember CreateAssociationEndMember(LoadMethodSessionState session, AssociationEndMember storeEndMember, UniqueIdentifierService usedEndMemberNames, RelationshipMultiplicity multiplicityOverride, OperationAction deleteBehaviorOverride) { Debug.Assert(storeEndMember.TypeUsage.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType, "The type is not a ref type"); Debug.Assert(((RefType)storeEndMember.TypeUsage.EdmType).ElementType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "the ref is not holding on to an EntityType"); EntityType storeEntityType = ((EntityType)((RefType)storeEndMember.TypeUsage.EdmType).ElementType); EntityType modelEntityType = session.MappingLookups.StoreEntityTypeToModelEntityType[storeEntityType]; string name = CreateModelName(storeEndMember.Name, usedEndMemberNames); AssociationEndMember end = new AssociationEndMember(name, modelEntityType.GetReferenceType(), multiplicityOverride); end.DeleteBehavior = deleteBehaviorOverride; return end; }
private AssociationSet CreateModelAssociationSet(LoadMethodSessionState session, AssociationSet storeAssociationSet) { AssociationType association; // we will get a value when the same association is used for multiple association sets if (! session.MappingLookups.StoreAssociationTypeToModelAssociationType.TryGetValue(storeAssociationSet.ElementType, out association)) { association = CreateModelAssociationType(session, storeAssociationSet.ElementType); session.MappingLookups.StoreAssociationTypeToModelAssociationType.Add(storeAssociationSet.ElementType, association); } string name = CreateModelName(storeAssociationSet.Name, session.UsedEntityContainerItemNames); AssociationSet set = new AssociationSet(name, association); foreach(AssociationSetEnd storeEnd in storeAssociationSet.AssociationSetEnds) { AssociationSetEnd end = CreateModelAssociationSetEnd(session, storeEnd, set); session.MappingLookups.StoreAssociationSetEndToModelAssociationSetEnd.Add(storeEnd, end); set.AddAssociationSetEnd(end); } session.MappingLookups.StoreAssociationSetToModelAssociationSet.Add(storeAssociationSet, set); return set; }
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] //For EdmItemCollection constructor call. //Since we pass in empty collection for paths, we do not have any resource exposure here. private IList<EdmSchemaError> InternalGenerateMetadata() { if (_modelEntityContainer != null) { _modelEntityContainer = null; _mappingLookups = null; _edmItemCollection = null; } LoadMethodSessionState session = new LoadMethodSessionState(); try { session.EdmItemCollection = new EdmItemCollection(); if (this.GenerateForeignKeyProperties && this._targetEntityFrameworkVersion < EntityFrameworkVersions.Version2) { session.AddError(Strings.UnableToGenerateForeignKeyPropertiesForV1, ModelBuilderErrorCode.UnableToGenerateForeignKeyPropertiesForV1, EdmSchemaErrorSeverity.Error, null); return session.Errors; } List<AssociationSet> storeAssociationSets = new List<AssociationSet>(); CollectAllFkProperties(session); EntityContainer modelEntityContainer = new EntityContainer(_modelEntityContainerName, DataSpace.CSpace); // create the EntityTypes and EntitySets, and save up the AssociationSets for later. foreach (EntitySetBase storeSet in _storeEntityContainer.BaseEntitySets) { switch (storeSet.BuiltInTypeKind) { case BuiltInTypeKind.AssociationSet: // save these, and create them after the EntityTypes and EntitySets have been created string errorMessage; if (this.GenerateForeignKeyProperties || !EntityStoreSchemaGenerator.IsFkPartiallyContainedInPK(((AssociationSet)storeSet).ElementType, out errorMessage)) { storeAssociationSets.Add((AssociationSet)storeSet); } else { session.AddError(errorMessage, ModelBuilderErrorCode.UnsupportedForeinKeyPattern, EdmSchemaErrorSeverity.Error, null); } break; case BuiltInTypeKind.EntitySet: EntitySet set = (EntitySet)storeSet; session.CandidateCollapsedAssociations.Add(set, new OneToOneMappingSerializer.CollapsedEntityAssociationSet(set)); break; default: // error throw EDesignUtil.MissingGenerationPatternForType(storeSet.BuiltInTypeKind); } } foreach (AssociationSet storeAssociationSet in storeAssociationSets) { SaveAssociationForCollapsedAssociationCandidate(session, storeAssociationSet); } Set<AssociationSet> associationSetsFromCollapseCandidateRejects = new Set<AssociationSet>(); IEnumerable<OneToOneMappingSerializer.CollapsedEntityAssociationSet> invalidCandidates = FindAllInvalidCollapsedAssociationCandidates(session); // now that we have gone through all of the association sets, foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in invalidCandidates) { session.CandidateCollapsedAssociations.Remove(collapsed.EntitySet); // just create the entity set and save the association set to be added later EntitySet entitySet = CreateModelEntitySet(session, collapsed.EntitySet); modelEntityContainer.AddEntitySetBase(entitySet); associationSetsFromCollapseCandidateRejects.AddRange(collapsed.AssociationSets); } // create all the associations for the invalid collapsed entity association candidates foreach (AssociationSet storeAssociationSet in (IEnumerable<AssociationSet>)associationSetsFromCollapseCandidateRejects) { if (!IsAssociationPartOfCandidateCollapsedAssociation(session, storeAssociationSet)) { AssociationSet set = CreateModelAssociationSet(session, storeAssociationSet); modelEntityContainer.AddEntitySetBase(set); } } // save the set that needs to be created and mapped session.MappingLookups.CollapsedEntityAssociationSets.AddRange(session.CandidateCollapsedAssociations.Values); // do this in a seperate loop so we are sure all the necessary EntitySets have been created foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet collapsed in session.MappingLookups.CollapsedEntityAssociationSets) { AssociationSet set = CreateModelAssociationSet(session, collapsed); modelEntityContainer.AddEntitySetBase(set); } if (this._targetEntityFrameworkVersion >= EntityFrameworkVersions.Version2) { Debug.Assert(EntityFrameworkVersions.Latest == EntityFrameworkVersions.Version3, "Did you add a new framework version"); // add LazyLoadingEnabled=true to the EntityContainer MetadataProperty lazyLoadingAttribute = new MetadataProperty( DesignXmlConstants.EdmAnnotationNamespace + ":" + DesignXmlConstants.LazyLoadingEnabled, TypeUsage.CreateStringTypeUsage( PrimitiveType.GetEdmPrimitiveType( PrimitiveTypeKind.String), false, false), true); modelEntityContainer.AddMetadataProperties(new List<MetadataProperty>() { lazyLoadingAttribute }); this._hasAnnotationNamespace = true; } // Map store functions to function imports. MapFunctions(session, modelEntityContainer); if (!EntityStoreSchemaGenerator.HasErrorSeverityErrors(session.Errors)) { // add them to the collection so they will work if someone wants to use the collection foreach (EntityType type in session.MappingLookups.StoreEntityTypeToModelEntityType.Values) { type.SetReadOnly(); session.EdmItemCollection.AddInternal(type); } foreach (AssociationType type in session.MappingLookups.StoreAssociationTypeToModelAssociationType.Values) { type.SetReadOnly(); session.EdmItemCollection.AddInternal(type); } foreach (OneToOneMappingSerializer.CollapsedEntityAssociationSet set in session.MappingLookups.CollapsedEntityAssociationSets) { set.ModelAssociationSet.ElementType.SetReadOnly(); session.EdmItemCollection.AddInternal(set.ModelAssociationSet.ElementType); } modelEntityContainer.SetReadOnly(); session.EdmItemCollection.AddInternal(modelEntityContainer); _modelEntityContainer = modelEntityContainer; _mappingLookups = session.MappingLookups; _edmItemCollection = session.EdmItemCollection; } } catch (Exception e) { if (MetadataUtil.IsCatchableExceptionType(e)) { // an exception in the code is definitely an error string message = EDesignUtil.GetMessagesFromEntireExceptionChain(e); session.AddError(message, ModelBuilderErrorCode.UnknownError, EdmSchemaErrorSeverity.Error, e); } else { throw; } } return session.Errors; }
private AssociationType CreateModelAssociationType(LoadMethodSessionState session, AssociationType storeAssociationType) { UniqueIdentifierService usedEndMemberNames = new UniqueIdentifierService(false); string name = CreateModelName(storeAssociationType.Name, session.UsedGlobalModelTypeNames); bool isFkAssociation = false; if (_targetEntityFrameworkVersion > EntityFrameworkVersions.Version1) { isFkAssociation = this.GenerateForeignKeyProperties || RequiresModelReferentialConstraint(storeAssociationType); } AssociationType association = new AssociationType(name, _namespaceName, isFkAssociation, DataSpace.CSpace); KeyValuePair<string, RelationshipMultiplicity> endMultiplicityOverride = CreateEndMultiplicityOverride(session, storeAssociationType, association); foreach (AssociationEndMember storeEndMember in storeAssociationType.RelationshipEndMembers) { AssociationEndMember end = CreateAssociationEndMember(session, storeEndMember, endMultiplicityOverride, usedEndMemberNames); session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember.Add(storeEndMember, end); association.AddMember(end); } ReferentialConstraint constraint = CreateReferentialConstraint(session, storeAssociationType); if (constraint != null) { association.AddReferentialConstraint(constraint); } CreateModelNavigationProperties(session, association); return association; }
private void MapFunctions(LoadMethodSessionState session, EntityContainer modelEntityContainer) { if (_storeFunctions == null || _storeFunctions.Length == 0 || _targetEntityFrameworkVersion < EntityFrameworkVersions.Version3) { return; } // // Create function imports and appropriate complex types for return parameters and add them to the item collection (session.EdmItemCollection). // Create and add function mappings. // var interestingStoreFunctions = _storeFunctions.Where( f => f.IsComposableAttribute && !f.AggregateAttribute && f.Parameters.All(p => p.Mode == ParameterMode.In)); foreach (var storeFunction in interestingStoreFunctions) { RowType tvfReturnType = TypeHelpers.GetTvfReturnType(storeFunction); if (tvfReturnType == null) { continue; } // Create function import name. string functionImportName = CreateModelName(storeFunction.Name, session.UsedEntityContainerItemNames); // Create function import parameters. UniqueIdentifierService usedParameterNames = new UniqueIdentifierService(false); var parameters = storeFunction.Parameters.Select(p => CreateFunctionImportParameter(p, usedParameterNames)).ToArray(); var failedStoreParameterName = storeFunction.Parameters.Select(p => p.Name).Except(parameters.Select(p => p.Name)).FirstOrDefault(); if (failedStoreParameterName != null) { session.AddError(Strings.UnableToGenerateFunctionImportParameterName(failedStoreParameterName, storeFunction.Identity), ModelBuilderErrorCode.UnableToGenerateFunctionImportParameterName, EdmSchemaErrorSeverity.Warning, null); continue; } // Create new complex type and register it in the item collection. var complexType = CreateModelComplexTypeForTvfResult(session, functionImportName, tvfReturnType); complexType.SetReadOnly(); session.EdmItemCollection.AddInternal(complexType); var collectionType = complexType.GetCollectionType(); collectionType.SetReadOnly(); var returnTypeUsage = TypeUsage.Create(collectionType); // Create function import and register it in the item collection. var functionImport = new EdmFunction(functionImportName, _modelEntityContainerName, DataSpace.CSpace, new EdmFunctionPayload() { Name = functionImportName, NamespaceName = _namespaceName, ReturnParameters = new FunctionParameter[] {new FunctionParameter(EdmConstants.ReturnType, returnTypeUsage, ParameterMode.ReturnValue)}, Parameters = parameters, DataSpace = DataSpace.CSpace, IsComposable = true, IsFunctionImport = true }); functionImport.SetReadOnly(); modelEntityContainer.AddFunctionImport(functionImport); // Add mapping tuple. session.MappingLookups.StoreFunctionToFunctionImport.Add(Tuple.Create(storeFunction, functionImport)); } }
private ReferentialConstraint CreateReferentialConstraint(LoadMethodSessionState session, AssociationType storeAssociation) { Debug.Assert(session != null, "session parameter is null"); Debug.Assert(storeAssociation != null, "storeAssociation parameter is null"); Debug.Assert(storeAssociation.ReferentialConstraints.Count <= 1, "We don't have a reason to have more than one constraint yet"); // does the store have any constraints if (storeAssociation.ReferentialConstraints.Count == 0) { return null; } ReferentialConstraint storeConstraint = storeAssociation.ReferentialConstraints[0]; Debug.Assert(storeConstraint.FromProperties.Count == storeConstraint.ToProperties.Count, "FromProperties and ToProperties have different counts"); Debug.Assert(storeConstraint.FromProperties.Count != 0, "No properties in the constraint, why does the constraint exist?"); Debug.Assert(storeConstraint.ToProperties[0].DeclaringType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "The property is not from an EntityType"); EntityType toType = (EntityType)storeConstraint.ToProperties[0].DeclaringType; // If we are generating foreign keys, there is always a referential constraint. Otherwise, check // if the dependent end includes key properties. If so, this implies that there is a referential // constraint. Otherwise, it is assumed that the foreign key properties are not defined in the // entity (verified ealier). if (!this.GenerateForeignKeyProperties && !RequiresModelReferentialConstraint(storeConstraint, toType)) { return null; } // we need a constraint so lets build it int count = storeConstraint.FromProperties.Count; EdmProperty[] fromProperties = new EdmProperty[count]; EdmProperty[] toProperties = new EdmProperty[count]; AssociationEndMember fromRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.FromRole]; AssociationEndMember toRole = session.MappingLookups.StoreAssociationEndMemberToModelAssociationEndMember[(AssociationEndMember)storeConstraint.ToRole]; for (int index = 0; index < count; index++) { fromProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.FromProperties[index]]; toProperties[index] = session.MappingLookups.StoreEdmPropertyToModelEdmProperty[storeConstraint.ToProperties[index]]; } ReferentialConstraint newConstraint = new ReferentialConstraint( fromRole, toRole, fromProperties, toProperties); return newConstraint; }
private AssociationSet CreateAssociationSet(LoadMethodSessionState session, AssociationType type) { AssociationSet set = new AssociationSet(type.Name, type); foreach(AssociationEndMember end in type.RelationshipEndMembers) { EntitySet entitySet = session.GetEntitySet(end); DbObjectKey key = session.GetKey(entitySet.ElementType); AssociationSetEnd setEnd = new AssociationSetEnd(entitySet, set, end); set.AddAssociationSetEnd(setEnd); } set.SetReadOnly(); return set; }