/// <summary> /// This helper function is an easy way to get a new entity type, entity set and key property in the /// new entity type created in the conceptual or storage model. /// NOTE: If the cpc already has an active transaction, these changes will be in that transaction /// and the caller of this helper method must commit it to see these changes commited. /// </summary> /// <param name="cpc"></param> /// <param name="name">The name of the new entity</param> /// <param name="setName">The name of the new set</param> /// <param name="createKeyProperty">A flag whether to create a new key property or not (sending false creates no new property)</param> /// <param name="propertyName">The name of the new property</param> /// <param name="propertyType">The type of the new property</param> /// <param name="modelSpace">Either Conceptual or Storage</param> /// <param name="uniquifyName">Flag whether the name should be checked for uniqueness and then changed as required</param> /// <param name="isDefaultName">Flag whether the name is the default for new entity types/sets</param> /// <returns>The new EntityType</returns> internal static EntityType CreateEntityTypeAndEntitySetAndProperty( CommandProcessorContext cpc, string name, string setName, bool createKeyProperty, string propertyName, string propertyType, string propertyStoreGeneratedPattern, ModelSpace modelSpace, bool uniquifyNames, bool isDefaultName = false) { var cp = new CommandProcessor(cpc); var cet = new CreateEntityTypeCommand(name, modelSpace, uniquifyNames); cet.CreateWithDefaultName = isDefaultName; cp.EnqueueCommand(cet); var ces = new CreateEntitySetCommand(setName, cet, modelSpace, uniquifyNames); cp.EnqueueCommand(ces); if (createKeyProperty) { var cpcd = new CreatePropertyCommand(propertyName, cet, propertyType, false); cpcd.IsIdProperty = true; cp.EnqueueCommand(cpcd); var skpc = new SetKeyPropertyCommand(cpcd, true); cp.EnqueueCommand(skpc); var ssgpc = new SetStoreGeneratedPatternCommand(cpcd, propertyStoreGeneratedPattern); cp.EnqueueCommand(ssgpc); } cp.Invoke(); return(cet.EntityType); }
protected override void InvokeInternal(CommandProcessorContext cpc) { // safety check, this should never be hit Debug.Assert(_derivedType != null, "InvokeInternal is called when DerivedType is null."); if (_derivedType == null) { throw new InvalidOperationException("InvokeInternal is called when DerivedType is null."); } // store off some local variables var baseType = _derivedType.BaseType.Target; var baseEntitySet = baseType.EntitySet as ConceptualEntitySet; var baseEntitySetMapping = (baseEntitySet == null ? null : baseEntitySet.EntitySetMapping); // save off a HashSet of all base types up the inheritance tree for searching later var allBaseTypes = new HashSet <EntityType>(); for (var baseEntityType = baseType; baseEntityType != null; baseEntityType = baseEntityType.BaseType.Target) { allBaseTypes.Add(baseEntityType); } // set up list of all derived types down the inheritance tree var derivedAndAllDerivedTypes = new List <ConceptualEntityType>(); derivedAndAllDerivedTypes.Add(_derivedType); derivedAndAllDerivedTypes.AddRange(_derivedType.ResolvableAllDerivedTypes); // remove any mappings which refer to properties which were inherited as these will // no longer be valid when the inheritance is deleted (and would cause the Mapping Details // window to open in non-edit mode). This must be done _before_ proceeding to clone the // EntityTypeMapping below and before we delete the inheritance (i.e. before the // DefaultableValue Target becomes unresolved). var scalarPropsToDelete = new List <ScalarProperty>(); if (allBaseTypes.Count > 0) { foreach (EntityType et in derivedAndAllDerivedTypes) { foreach (var etm in et.GetAntiDependenciesOfType <EntityTypeMapping>()) { foreach (var mf in etm.MappingFragments()) { foreach (var sp in mf.AllScalarProperties()) { var prop = sp.Name.Target; if (prop != null) { // find EntityType of which this Property is a member var propEntityType = prop.GetParentOfType(typeof(EntityType)) as EntityType; if (propEntityType != null && allBaseTypes.Contains(propEntityType)) { // sp references a Property of an EntityType which will no longer // be in the inheritance hierarchy - so delete the mapping scalarPropsToDelete.Add(sp); } } } } } } } // cannot delete the ScalarProperty while enumerating over them - so instead delete in separate loop below foreach (var sp in scalarPropsToDelete) { DeleteEFElementCommand.DeleteInTransaction(cpc, sp); } // remove the inheritance _derivedType.BaseType.SetRefName(null); // re-resolve the derived type. This will set the state of the _derivedType to be resolved (it could be unresolved because base-type binding could have been a duplicate or unknown binding). _derivedType.State = EFElementState.Normalized; _derivedType.Resolve(_derivedType.Artifact.ArtifactSet); // the entity container we want to add it to var entityContainer = _derivedType.EntityModel.EntityContainer; Debug.Assert(entityContainer != null, "DerivedType does not have an Entity Container"); // since this type no longer derives, it is stand alone and needs its own entity set // derive a name for the new entity set and create it var trialSetName = ModelHelper.ConstructProposedEntitySetName(_derivedType.Artifact, _derivedType.LocalName.Value); var ces = new CreateEntitySetCommand(trialSetName, _derivedType, true); CommandProcessor.InvokeSingleCommand(cpc, ces); var newEntitySet = ces.EntitySet as ConceptualEntitySet; // if the old entityset had mappings, then some may need to be moved if (baseEntitySetMapping != null) { // create a new EntitySetMapping for the new EntitySet that we made for the formally derivedType var createESM = new CreateEntitySetMappingCommand(entityContainer.EntityContainerMapping, newEntitySet); CommandProcessor.InvokeSingleCommand(cpc, createESM); var newEntitySetMapping = createESM.EntitySetMapping; // this type no longer derives from the type it used to, so its mappings can no longer // exist under the old EntitySetMapping, so we need to move them // move any EntityTypeMappings from the old EntitySetMapping used by the former base type // to the new one created for the new EntitySet and EntitySetMapping foreach (EntityType changingType in derivedAndAllDerivedTypes) { var etms = new List <EntityTypeMapping>(); etms.AddRange(changingType.GetAntiDependenciesOfType <EntityTypeMapping>()); foreach (var etm in etms) { // here, to work around an xml editor bug, we clone the entity type mapping, instead of re-parenting it var newetm = etm.Clone(newEntitySetMapping); // now delete the old entity type mapping & dispose it. DeleteEFElementCommand.DeleteInTransaction(cpc, etm); } } } // // if there are any referential constraints properties whose principal ends refer to keys in the // old derived type, delete them // foreach (var end in _derivedType.GetAntiDependenciesOfType <AssociationEnd>()) { foreach (var role in end.GetAntiDependenciesOfType <ReferentialConstraintRole>()) { var rc = role.Parent as ReferentialConstraint; if (rc != null && rc.Principal == role) { foreach (var pr in rc.Principal.PropertyRefs) { Command cmd = new DeleteReferentialConstraintPropertyRefCommand(pr); // don't invoke this command now, as it will modify the collection we're iterating over CommandProcessor.EnqueueCommand(cmd); } } } } }
/// <summary> /// This helper function is an easy way to get a new entity type, entity set and key property in the /// new entity type created in the conceptual or storage model. /// NOTE: If the cpc already has an active transaction, these changes will be in that transaction /// and the caller of this helper method must commit it to see these changes commited. /// </summary> /// <param name="cpc"></param> /// <param name="name">The name of the new entity</param> /// <param name="setName">The name of the new set</param> /// <param name="createKeyProperty">A flag whether to create a new key property or not (sending false creates no new property)</param> /// <param name="propertyName">The name of the new property</param> /// <param name="propertyType">The type of the new property</param> /// <param name="modelSpace">Either Conceptual or Storage</param> /// <param name="uniquifyName">Flag whether the name should be checked for uniqueness and then changed as required</param> /// <param name="isDefaultName">Flag whether the name is the default for new entity types/sets</param> /// <returns>The new EntityType</returns> internal static EntityType CreateEntityTypeAndEntitySetAndProperty( CommandProcessorContext cpc, string name, string setName, bool createKeyProperty, string propertyName, string propertyType, string propertyStoreGeneratedPattern, ModelSpace modelSpace, bool uniquifyNames, bool isDefaultName = false) { var cp = new CommandProcessor(cpc); var cet = new CreateEntityTypeCommand(name, modelSpace, uniquifyNames); cet.CreateWithDefaultName = isDefaultName; cp.EnqueueCommand(cet); var ces = new CreateEntitySetCommand(setName, cet, modelSpace, uniquifyNames); cp.EnqueueCommand(ces); if (createKeyProperty) { var cpcd = new CreatePropertyCommand(propertyName, cet, propertyType, false); cpcd.IsIdProperty = true; cp.EnqueueCommand(cpcd); var skpc = new SetKeyPropertyCommand(cpcd, true); cp.EnqueueCommand(skpc); var ssgpc = new SetStoreGeneratedPatternCommand(cpcd, propertyStoreGeneratedPattern); cp.EnqueueCommand(ssgpc); } cp.Invoke(); return cet.EntityType; }
protected override void InvokeInternal(CommandProcessorContext cpc) { // safety check, this should never be hit Debug.Assert(_derivedType != null, "InvokeInternal is called when DerivedType is null."); if (_derivedType == null) { throw new InvalidOperationException("InvokeInternal is called when DerivedType is null."); } // store off some local variables var baseType = _derivedType.BaseType.Target; var baseEntitySet = baseType.EntitySet as ConceptualEntitySet; var baseEntitySetMapping = (baseEntitySet == null ? null : baseEntitySet.EntitySetMapping); // save off a HashSet of all base types up the inheritance tree for searching later var allBaseTypes = new HashSet<EntityType>(); for (var baseEntityType = baseType; baseEntityType != null; baseEntityType = baseEntityType.BaseType.Target) { allBaseTypes.Add(baseEntityType); } // set up list of all derived types down the inheritance tree var derivedAndAllDerivedTypes = new List<ConceptualEntityType>(); derivedAndAllDerivedTypes.Add(_derivedType); derivedAndAllDerivedTypes.AddRange(_derivedType.ResolvableAllDerivedTypes); // remove any mappings which refer to properties which were inherited as these will // no longer be valid when the inheritance is deleted (and would cause the Mapping Details // window to open in non-edit mode). This must be done _before_ proceeding to clone the // EntityTypeMapping below and before we delete the inheritance (i.e. before the // DefaultableValue Target becomes unresolved). var scalarPropsToDelete = new List<ScalarProperty>(); if (allBaseTypes.Count > 0) { foreach (EntityType et in derivedAndAllDerivedTypes) { foreach (var etm in et.GetAntiDependenciesOfType<EntityTypeMapping>()) { foreach (var mf in etm.MappingFragments()) { foreach (var sp in mf.AllScalarProperties()) { var prop = sp.Name.Target; if (prop != null) { // find EntityType of which this Property is a member var propEntityType = prop.GetParentOfType(typeof(EntityType)) as EntityType; if (propEntityType != null && allBaseTypes.Contains(propEntityType)) { // sp references a Property of an EntityType which will no longer // be in the inheritance hierarchy - so delete the mapping scalarPropsToDelete.Add(sp); } } } } } } } // cannot delete the ScalarProperty while enumerating over them - so instead delete in separate loop below foreach (var sp in scalarPropsToDelete) { DeleteEFElementCommand.DeleteInTransaction(cpc, sp); } // remove the inheritance _derivedType.BaseType.SetRefName(null); // re-resolve the derived type. This will set the state of the _derivedType to be resolved (it could be unresolved because base-type binding could have been a duplicate or unknown binding). _derivedType.State = EFElementState.Normalized; _derivedType.Resolve(_derivedType.Artifact.ArtifactSet); // the entity container we want to add it to var entityContainer = _derivedType.EntityModel.EntityContainer; Debug.Assert(entityContainer != null, "DerivedType does not have an Entity Container"); // since this type no longer derives, it is stand alone and needs its own entity set // derive a name for the new entity set and create it var trialSetName = ModelHelper.ConstructProposedEntitySetName(_derivedType.Artifact, _derivedType.LocalName.Value); var ces = new CreateEntitySetCommand(trialSetName, _derivedType, true); CommandProcessor.InvokeSingleCommand(cpc, ces); var newEntitySet = ces.EntitySet as ConceptualEntitySet; // if the old entityset had mappings, then some may need to be moved if (baseEntitySetMapping != null) { // create a new EntitySetMapping for the new EntitySet that we made for the formally derivedType var createESM = new CreateEntitySetMappingCommand(entityContainer.EntityContainerMapping, newEntitySet); CommandProcessor.InvokeSingleCommand(cpc, createESM); var newEntitySetMapping = createESM.EntitySetMapping; // this type no longer derives from the type it used to, so its mappings can no longer // exist under the old EntitySetMapping, so we need to move them // move any EntityTypeMappings from the old EntitySetMapping used by the former base type // to the new one created for the new EntitySet and EntitySetMapping foreach (EntityType changingType in derivedAndAllDerivedTypes) { var etms = new List<EntityTypeMapping>(); etms.AddRange(changingType.GetAntiDependenciesOfType<EntityTypeMapping>()); foreach (var etm in etms) { // here, to work around an xml editor bug, we clone the entity type mapping, instead of re-parenting it var newetm = etm.Clone(newEntitySetMapping); // now delete the old entity type mapping & dispose it. DeleteEFElementCommand.DeleteInTransaction(cpc, etm); } } } // // if there are any referential constraints properties whose principal ends refer to keys in the // old derived type, delete them // foreach (var end in _derivedType.GetAntiDependenciesOfType<AssociationEnd>()) { foreach (var role in end.GetAntiDependenciesOfType<ReferentialConstraintRole>()) { var rc = role.Parent as ReferentialConstraint; if (rc != null && rc.Principal == role) { foreach (var pr in rc.Principal.PropertyRefs) { Command cmd = new DeleteReferentialConstraintPropertyRefCommand(pr); // don't invoke this command now, as it will modify the collection we're iterating over CommandProcessor.EnqueueCommand(cmd); } } } } }