protected override void BuildNew(CommandProcessorContext cpc, string propertyName, string propertyType) { if (StorageEntityType == null || ConceptualEntityType == null) { Debug.Fail("The AssociationSetEndMappingBuilder does not have references to everything it needs"); return; } // try to find the column with this name var tableColumn = StorageEntityType.GetFirstNamedChildByLocalName(propertyName, true) as Property; if (tableColumn != null) { // now see if there is also a property with this name var entityProperty = ConceptualEntityType.GetFirstNamedChildByLocalName(propertyName) as Property; if (entityProperty == null) { // they might be trying to map a key from the base class EntityType topMostBaseType = ConceptualEntityType.ResolvableTopMostBaseType; entityProperty = topMostBaseType.GetFirstNamedChildByLocalName(propertyName) as Property; } // if we have both, create a mapping if (entityProperty != null) { CreateEndScalarPropertyCommand cmd = null; var end = AssociationSetEnd.EndProperty; if (end == null) { // we don't have an end yet, this version will create an end as well as the scalar property cmd = new CreateEndScalarPropertyCommand( AssociationSet.AssociationSetMapping, AssociationSetEnd, entityProperty, tableColumn); } else { cmd = new CreateEndScalarPropertyCommand(end, entityProperty, tableColumn); } CommandProcessor.InvokeSingleCommand(cpc, cmd); } } }
protected override void InvokeInternal(CommandProcessorContext cpc) { var endProperty = AssociationSetMapping.EndProperties().FirstOrDefault( ep => string.Equals(ep.Name.XAttribute.Value, AssociationSetEnd.GetRefNameForBinding(ep.Name), StringComparison.CurrentCulture)); // EndProperty does not exist, create it if (endProperty == null) { base.InvokeInternal(cpc); endProperty = EndProperty; Debug.Assert(endProperty != null, "Could not create end property"); } // Update Scalar properties if (endProperty != null) { var oldScalarProperties = endProperty.ScalarProperties().ToList(); foreach (var oldProperty in oldScalarProperties) { oldProperty.Delete(); } Debug.Assert( ConceptualKeyProperties.Count() == StorageKeyProperties.Count(), "Found different number of keys in storage and conceptual models"); var conceptualEnumerator = ConceptualKeyProperties.GetEnumerator(); var storageEnumerator = StorageKeyProperties.GetEnumerator(); while (conceptualEnumerator.MoveNext() && storageEnumerator.MoveNext()) { var createEndScalarCommand = new CreateEndScalarPropertyCommand( endProperty, conceptualEnumerator.Current, storageEnumerator.Current); CommandProcessor.InvokeSingleCommand(cpc, createEndScalarCommand); } } }
// <summary> // The mapping view model contains a MappingEndScalarProperty for every key in each end. The user can clear out the // underlying scalar property, but that doesn't remove or add the MappingEndScalarProperty. We need the placeholder // in the view model to show the nodes in the Trid even if there isn't a mapping. Thus, we don't need to call // this.Parent.AddChild(this) since its already there. // </summary> internal override void CreateModelItem(CommandProcessorContext cpc, EditingContext context, EFElement underlyingModelItem) { Debug.Assert(underlyingModelItem != null, "The underlyingModelItem cannot be null"); var tableColumn = underlyingModelItem as Property; Debug.Assert(context != null, "The context argument cannot be null"); Debug.Assert(ScalarProperty == null, "Don't call this method if we already have a ModelItem"); Debug.Assert(tableColumn != null, "The tableColumn cannot be null."); if (tableColumn == null) { return; } Debug.Assert(tableColumn.EntityType.EntityModel.IsCSDL == false, "tableColumn must be a Store-side Property"); Context = context; // find the c-side property based on the passed in name var entityProperty = MappingAssociationSetEnd.ConceptualEntityType.GetFirstNamedChildByLocalName(Property) as Property; if (entityProperty == null) { // they might be trying to map a key from the base class EntityType topMostBaseType = MappingAssociationSetEnd.ConceptualEntityType.ResolvableTopMostBaseType; entityProperty = topMostBaseType.GetFirstNamedChildByLocalName(Property) as Property; } Debug.Assert(entityProperty != null, "Failed looking up entity property for ScalarProperty."); if (entityProperty == null) { return; } // create our context if we don't have one if (cpc == null) { cpc = new CommandProcessorContext( Context, EfiTransactionOriginator.MappingDetailsOriginatorId, Resources.Tx_CreateScalarProperty); } // create the right command CreateEndScalarPropertyCommand cmd = null; var end = MappingAssociationSetEnd.AssociationSetEnd.EndProperty; if (end == null) { // we don't have an end yet, this version will create an end as well as the scalar property cmd = new CreateEndScalarPropertyCommand( MappingAssociationSet.AssociationSet.AssociationSetMapping, MappingAssociationSetEnd.AssociationSetEnd, entityProperty, tableColumn); } else { cmd = new CreateEndScalarPropertyCommand(end, entityProperty, tableColumn); } // set up our post event to fix up the view model cmd.PostInvokeEvent += (o, eventArgs) => { var sp = cmd.ScalarProperty; Debug.Assert(sp != null, "cmd failed to generate ScalarProperty"); // fix up our view model (we don't have to add this to the parent's children collection // because we created a placeholder row already for every key in the entity) ModelItem = sp; }; try { // now make the change var cp = new CommandProcessor(cpc, cmd); cp.Invoke(); } catch { ModelItem = null; throw; } }
private EndProperty CloneEndProperty( CommandProcessorContext cpc, EndProperty endToClone, AssociationSetMapping asmInExistingArtifact, AssociationSetEnd aseInExistingArtifact, Dictionary<EntityType, EntityType> tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact) { var createEnd = new CreateEndPropertyCommand(asmInExistingArtifact, aseInExistingArtifact); CommandProcessor.InvokeSingleCommand(cpc, createEnd); var endInExistingArtifact = createEnd.EndProperty; if (null == endInExistingArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseCannotCreateAssociationSetMappingEndProperty, aseInExistingArtifact.ToPrettyString())); } var existingArtifact = cpc.Artifact; Debug.Assert(existingArtifact != null, "existingArtifact is null for endToClone " + endToClone.ToPrettyString()); foreach (var sp in endToClone.ScalarProperties()) { if (null == sp.Name.Target) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseScalarPropertyNoNameTarget, sp.ToPrettyString())); } if (null == sp.ColumnName.Target) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseScalarPropertyNoColumnNameTarget, sp.ToPrettyString())); } var spCSideEntityTypeinTempArtifact = sp.Name.Target.EntityType as ConceptualEntityType; if (null == spCSideEntityTypeinTempArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindEntityTypeForProperty, sp.Name.Target.ToPrettyString())); } var spSSideEntityTypeinTempArtifact = sp.ColumnName.Target.EntityType as StorageEntityType; if (null == spSSideEntityTypeinTempArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindEntityTypeForProperty, sp.ColumnName.Target.ToPrettyString())); } var csdlEntityTypeInExistingArtifact = FindMatchingConceptualEntityTypeInExistingArtifact( spCSideEntityTypeinTempArtifact, tempArtifactCEntityTypeToNewCEntityTypeInExistingArtifact); if (null == csdlEntityTypeInExistingArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindMatchingEntityType, sp.ToPrettyString(), spCSideEntityTypeinTempArtifact.ToPrettyString())); } var ssdlEntityTypeInExistingArtifact = FindMatchingStorageEntityTypeInExistingArtifact(spSSideEntityTypeinTempArtifact); if (null == ssdlEntityTypeInExistingArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindMatchingEntityType, sp.ToPrettyString(), spSSideEntityTypeinTempArtifact.ToPrettyString())); } var entityProperty = FindMatchingPropertyInExistingArtifactEntityType(sp.Name.Target, csdlEntityTypeInExistingArtifact); if (null == entityProperty) { // Cannot find matching property - it must have been unmapped. // So try to create a new mapped property to which to attach // this association. // First find S-side Property in temp artifact to which the C-side // Property identified in the AssociationSetMapping is mapped // (Note: cannot use just sp.ColumnName.Target as the S-side Property // used in the AssociationSetMapping can be different from what is used // for the EntitySetMapping in the temp artifact and it is this latter // we need to replicate here). Property sSidePropertyToBeMappedInTempArtifact = null; foreach (var spInTempArtifact in sp.Name.Target.GetAntiDependenciesOfType<ScalarProperty>()) { // Ensure that S-side ScalarProperty is from an EntitySetMapping (and not // an AssociationSetMapping) in the temp artifact. // Can use first one as in temp artifact there is 1:1 mapping. if (null != spInTempArtifact.GetParentOfType(typeof(EntitySetMapping))) { if (null != spInTempArtifact.ColumnName && null != spInTempArtifact.ColumnName.Target) { if (null == sSidePropertyToBeMappedInTempArtifact) { sSidePropertyToBeMappedInTempArtifact = spInTempArtifact.ColumnName.Target; } else { // error in temp artifact - there's more than 1 EntitySetMapping ScalarProperty // mapped to the C-side Property Debug.Fail( "C-side Property " + sp.Name.Target.ToPrettyString() + " has more than 1 ScalarProperty anti-dep with an EntitySetMapping parent. Should be at most 1."); break; } } } } if (null == sSidePropertyToBeMappedInTempArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindSSideForCSideProperty, sp.ToPrettyString(), sp.Name.Target.ToPrettyString())); } // Now find the matching S-side Property in the existing artifact var sSidePropertyToBeMappedInExistingArtifact = FindSSidePropInExistingArtifact(sSidePropertyToBeMappedInTempArtifact); if (null == sSidePropertyToBeMappedInExistingArtifact) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindMatchingSSideProperty, sp.ToPrettyString(), sSidePropertyToBeMappedInTempArtifact.ToPrettyString())); } // Now create a new C-side Property in the existing artifact mapped // to the S-side Property we just found entityProperty = CreateNewConceptualPropertyAndMapping( cpc, sp.Name.Target, sSidePropertyToBeMappedInTempArtifact, csdlEntityTypeInExistingArtifact); if (null == entityProperty) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindOrCreateMatchingProperty, sp.ToPrettyString(), sp.Name.Target.ToPrettyString(), csdlEntityTypeInExistingArtifact.ToPrettyString())); } } var tableColumn = FindMatchingPropertyInExistingArtifactEntityType(sp.ColumnName.Target, ssdlEntityTypeInExistingArtifact); if (null == tableColumn) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseAssociationSetMappingCannotFindMatchingProperty, sp.ToPrettyString(), sp.ColumnName.Target.ToPrettyString(), ssdlEntityTypeInExistingArtifact.ToPrettyString())); } var createScalar = new CreateEndScalarPropertyCommand(endInExistingArtifact, entityProperty, tableColumn); CommandProcessor.InvokeSingleCommand(cpc, createScalar); var existingScalarProp = createScalar.ScalarProperty; if (null == existingScalarProp) { throw new UpdateModelFromDatabaseException( string.Format( CultureInfo.CurrentCulture, Resources.UpdateFromDatabaseCannotCreateAssociationSetMappingScalarProperty, entityProperty.ToPrettyString(), tableColumn.ToPrettyString())); } } return endInExistingArtifact; }