internal ForeignKeyConstraint(md.RelationshipType relType, md.RelationshipSet relationshipSet, md.ReferentialConstraint constraint) { md.AssociationSet assocSet = relationshipSet as md.AssociationSet; md.AssociationEndMember fromEnd = constraint.FromRole as md.AssociationEndMember; md.AssociationEndMember toEnd = constraint.ToRole as md.AssociationEndMember; // Currently only Associations are supported if (null == assocSet || null == fromEnd || null == toEnd) { throw EntityUtil.NotSupported(); } m_constraint = constraint; md.EntitySet parent = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, fromEnd); // relationshipSet.GetRelationshipEndExtent(constraint.FromRole); md.EntitySet child = System.Data.Common.Utils.MetadataHelper.GetEntitySetAtEnd(assocSet, toEnd); // relationshipSet.GetRelationshipEndExtent(constraint.ToRole); m_extentPair = new ExtentPair(parent, child); m_childKeys = new List <string>(); foreach (md.EdmProperty prop in constraint.ToProperties) { m_childKeys.Add(prop.Name); } m_parentKeys = new List <string>(); foreach (md.EdmProperty prop in constraint.FromProperties) { m_parentKeys.Add(prop.Name); } PlanCompiler.Assert((md.RelationshipMultiplicity.ZeroOrOne == fromEnd.RelationshipMultiplicity || md.RelationshipMultiplicity.One == fromEnd.RelationshipMultiplicity), "from-end of relationship constraint cannot have multiplicity greater than 1"); }
private void InitializeForeignKeyLists() { var dependents = new List <Tuple <AssociationSet, ReferentialConstraint> >(); var principals = new List <Tuple <AssociationSet, ReferentialConstraint> >(); bool foundFkRelationship = false; bool foundIndependentRelationship = false; foreach (AssociationSet associationSet in MetadataHelper.GetAssociationsForEntitySet(this)) { if (associationSet.ElementType.IsForeignKey) { foundFkRelationship = true; Debug.Assert(associationSet.ElementType.ReferentialConstraints.Count == 1, "Expected exactly one constraint for FK"); ReferentialConstraint constraint = associationSet.ElementType.ReferentialConstraints[0]; if (constraint.ToRole.GetEntityType().IsAssignableFrom(this.ElementType) || this.ElementType.IsAssignableFrom(constraint.ToRole.GetEntityType())) { // Dependents dependents.Add(new Tuple <AssociationSet, ReferentialConstraint>(associationSet, constraint)); } if (constraint.FromRole.GetEntityType().IsAssignableFrom(this.ElementType) || this.ElementType.IsAssignableFrom(constraint.FromRole.GetEntityType())) { // Principals principals.Add(new Tuple <AssociationSet, ReferentialConstraint>(associationSet, constraint)); } } else { foundIndependentRelationship = true; } } _hasForeignKeyRelationships = foundFkRelationship; _hasIndependentRelationships = foundIndependentRelationship; var readOnlyDependents = dependents.AsReadOnly(); var readOnlyPrincipals = principals.AsReadOnly(); Interlocked.CompareExchange(ref _foreignKeyDependents, readOnlyDependents, null); Interlocked.CompareExchange(ref _foreignKeyPrincipals, readOnlyPrincipals, null); }
private bool IsEntityDependentSideOfBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return ((RefType)constraint0.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType && ((RefType)constraint1.ToRole.TypeUsage.EdmType).ElementType == _storeEntitySet.ElementType; }
private static void AddToPropertyNames(ReferentialConstraint constraint, Set<string> names) { foreach (EdmProperty property in constraint.ToProperties) { names.Add(property.Name); } }
private bool AreAllEntityColumnsMappedAsToColumns(ReferentialConstraint constraint0, ReferentialConstraint constraint1) { Set<string> names = new Set<string>(); AddToPropertyNames(constraint0, names); AddToPropertyNames(constraint1, names); return names.Count == _storeEntitySet.ElementType.Properties.Count; }
internal override bool CheckReferentialConstraintDependentProperty(EntityEntry ownerEntry, ReferentialConstraint constraint) { // if the related end contains a real entity or is a reference with a detached entitykey, we need to check for RI constraints if (!IsEmpty()) { return base.CheckReferentialConstraintDependentProperty(ownerEntry, constraint); } else if ((ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne || ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) && DetachedEntityKey != null) { // related end is empty, so we must have a reference with a detached key var detachedKey = DetachedEntityKey; #if DEBUG // If the constraint is not PK<->PK then we can't validate it here. // This debug code checks that we don't try to validate it. var keyNames = new List<string>( from v in detachedKey.EntityKeyValues select v.Key); foreach (var prop in constraint.ToProperties) { Debug.Assert( keyNames.Contains(prop.Name), "Attempt to validate constraint where some FK values are not in the dependent PK"); } #endif // don't need to validate the principal/detached key here because that has already been done during AttachContext if (!VerifyRIConstraintsWithRelatedEntry(constraint, detachedKey.FindValueByName, ownerEntry.EntityKey)) { return false; } } return true; }
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; }
/// <summary> /// Add the given referential constraint to the collection of referential constraints /// </summary> /// <param name="referentialConstraint"></param> internal void AddReferentialConstraint(ReferentialConstraint referentialConstraint) { this.ReferentialConstraints.Source.Add(referentialConstraint); }
protected virtual void Visit(ReferentialConstraint referentialConstraint) { foreach (var property in referentialConstraint.FromProperties) { Visit(property); } Visit(referentialConstraint.FromRole); foreach (var property in referentialConstraint.ToProperties) { Visit(property); } Visit(referentialConstraint.ToRole); }
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; }
/// <summary> /// Creates an EntityKey for a principal entity based on the foreign key values contained /// in this entity. This implies that this entity is at the dependent end of the relationship. /// </summary> /// <param name="dependentEntry">The EntityEntry for the dependent that contains the FK</param> /// <param name="constraint">The constraint that describes this FK relationship</param> /// <param name="principalEntitySet">The entity set at the principal end of the the relationship</param> /// <param name="useOriginalValues">If true then the key will be constructed from the original FK values</param> /// <returns>The key, or null if any value in the key is null</returns> public static EntityKey CreateKeyFromForeignKeyValues(EntityEntry dependentEntry, ReferentialConstraint constraint, EntitySet principalEntitySet, bool useOriginalValues) { // Build the key values. If any part of the key is null, then the entire key // is considered null. var dependentProps = constraint.ToProperties; int numValues = dependentProps.Count; if (numValues == 1) { object keyValue = useOriginalValues ? dependentEntry.GetOriginalEntityValue(dependentProps.First().Name) : dependentEntry.GetCurrentEntityValue(dependentProps.First().Name); return keyValue == DBNull.Value ? null : new EntityKey(principalEntitySet, keyValue); } // Note that the properties in the principal entity set may be in a different order than // they appear in the constraint. Therefore, we create name value mappings to ensure that // the correct values are associated with the correct properties. // Unfortunately, there is not way to call the public EntityKey constructor that takes pairs // because the internal "object" constructor hides it. Even this doesn't work: // new EntityKey(principalEntitySet, (IEnumerable<KeyValuePair<string, object>>)keyValues) string[] keyNames = principalEntitySet.ElementType.KeyMemberNames; Debug.Assert(keyNames.Length == numValues, "Number of entity set key names does not match constraint names"); object[] values = new object[numValues]; var principalProps = constraint.FromProperties; for (int i = 0; i < numValues; i++) { object value = useOriginalValues ? dependentEntry.GetOriginalEntityValue(dependentProps[i].Name) : dependentEntry.GetCurrentEntityValue(dependentProps[i].Name); if (value == DBNull.Value) { return null; } int keyIndex = Array.IndexOf(keyNames, principalProps[i].Name); Debug.Assert(keyIndex >= 0 && keyIndex < numValues, "Could not find constraint prop name in entity set key names"); values[keyIndex] = value; } return new EntityKey(principalEntitySet, values); }
public virtual string WriteForeignKeyUpdateAction(ReferentialConstraint refConstraint) { return "ON UPDATE NO ACTION"; }
public virtual string WriteForeignKeyDeleteAction(ReferentialConstraint refConstraint) { return refConstraint.FromRole.DeleteBehavior == OperationAction.Cascade ? "ON DELETE CASCADE" : "ON DELETE NO ACTION"; }
public virtual string GetForeignKeyConstraintName(ReferentialConstraint constraint) { var name = constraint.FromRole.DeclaringType.Name; if (!name.StartsWith("FK_", StringComparison.InvariantCultureIgnoreCase)) { name = "FK_" + name; } return name; }
private void GetConstraints(out ReferentialConstraint constraint0, out ReferentialConstraint constraint1) { Debug.Assert(_storeAssociationSets.Count == 2, "don't call this method if you don't have two associations"); Debug.Assert(_storeAssociationSets[0].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[0]"); Debug.Assert(_storeAssociationSets[1].ElementType.ReferentialConstraints.Count == 1, "no referenctial constraint for association[1]"); constraint0 = _storeAssociationSets[0].ElementType.ReferentialConstraints[0]; constraint1 = _storeAssociationSets[1].ElementType.ReferentialConstraints[0]; }
protected override void Visit(ReferentialConstraint referentialConstraint) { int index; if (!this.AddObjectToSeenListAndHashBuilder(referentialConstraint, out index)) { return; } this.AddObjectStartDumpToHashBuilder(referentialConstraint, index); #region Inner data visit this.AddObjectContentToHashBuilder(referentialConstraint.Identity); base.Visit(referentialConstraint); #endregion this.AddObjectEndDumpToHashBuilder(); }
/// <summary> /// Add the given referential constraint to the collection of referential constraints /// </summary> /// <param name="referentialConstraint"></param> internal void AddReferentialConstraint(ReferentialConstraint referentialConstraint) { ReferentialConstraints.Source.Add(referentialConstraint); }
private bool IsAtLeastOneColumnFKInBothAssociations(ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return constraint1.ToProperties.Any(c => constraint0.ToProperties.Contains(c)); }
private static bool RequiresModelReferentialConstraint(ReferentialConstraint storeConstraint, EntityType toType) { return toType.KeyMembers.Contains(storeConstraint.ToProperties[0]); }
private bool IsAtLeastOneColumnOfBothDependentRelationshipColumnSetsNonNullable(ReferentialConstraint constraint0, ReferentialConstraint constraint1) { return ToPropertyHasNonNullableColumn(constraint0) && ToPropertyHasNonNullableColumn(constraint1); }
// Check if related entities contain proper property values internal override bool CheckReferentialConstraintPrincipalProperty(EntityEntry ownerEntry, ReferentialConstraint constraint) { EntityKey principalKey; if (!IsEmpty()) { var wrappedRelatedEntity = ReferenceValue; // For Added entities, it doesn't matter what the key value is since it can't be trusted anyway. if (wrappedRelatedEntity.ObjectStateEntry != null && wrappedRelatedEntity.ObjectStateEntry.State == EntityState.Added) { return true; } principalKey = ExtractPrincipalKey(wrappedRelatedEntity); } else if ((ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne || ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One) && DetachedEntityKey != null) { // Generally for foreign keys we want to use the EntityKey to do RI constraint validation // However, if we are doing an Add/Attach, we should use the DetachedEntityKey because this is the value // set by the user while the entity was detached, and should be used until the entity is fully added/attached if (IsForeignKey && !(ObjectContext.ObjectStateManager.TransactionManager.IsAddTracking || ObjectContext.ObjectStateManager.TransactionManager.IsAttachTracking)) { principalKey = EntityKey; } else { principalKey = DetachedEntityKey; } } else { // We only need to check for RI constraints if the related end contains a real entity or is a reference with a detached entitykey return true; } return VerifyRIConstraintsWithRelatedEntry(constraint, ownerEntry.GetCurrentEntityValue, principalKey); }
private static bool ToPropertyHasNonNullableColumn(ReferentialConstraint constraint) { foreach (EdmProperty property in constraint.ToProperties) { if (!property.Nullable) { return true; } } return false; }
private static DbRelatedEntityRef RelatedEntityRefFromAssociationSetEnd(EntityType constructedEntityType, DbNewInstanceExpression entityConstructor, AssociationSetEnd principalSetEnd, ReferentialConstraint fkConstraint) { EntityType principalEntityType = (EntityType)TypeHelpers.GetEdmType<RefType>(fkConstraint.FromRole.TypeUsage).ElementType; IList<DbExpression> principalKeyValues = null; // Create Entity Property/DbExpression value pairs from the entity constructor DbExpression, // then join these with the principal/dependent property pairs from the FK constraint // to produce principal property name/DbExpression value pairs from which to create the principal ref. // // Ideally the code would be as below, but anonymous types break asmmeta: //var keyPropAndValue = // from pv in constructedEntityType.Properties.Select((p, idx) => new { DependentProperty = p, Value = entityConstructor.Arguments[idx] }) // join ft in fkConstraint.FromProperties.Select((fp, idx) => new { PrincipalProperty = fp, DependentProperty = fkConstraint.ToProperties[idx] }) // on pv.DependentProperty equals ft.DependentProperty // select new { PrincipalProperty = ft.PrincipalProperty.Name, Value = pv.Value }; // var keyPropAndValue = from pv in constructedEntityType.Properties.Select((p, idx) => Tuple.Create(p, entityConstructor.Arguments[idx])) // new { DependentProperty = p, Value = entityConstructor.Arguments[idx] }) join ft in fkConstraint.FromProperties.Select((fp, idx) => Tuple.Create(fp, fkConstraint.ToProperties[idx])) //new { PrincipalProperty = fp, DependentProperty = fkConstraint.ToProperties[idx] }) on pv.Item1 equals ft.Item2 //pv.DependentProperty equals ft.DependentProperty select Tuple.Create(ft.Item1.Name, pv.Item2); // new { PrincipalProperty = ft.PrincipalProperty.Name, Value = pv.Value }; // If there is only a single property in the principal's key, then there is no ordering concern. // Otherwise, create a dictionary of principal key property name to DbExpression value so that // when used as the arguments to the ref expression, the dependent property values - used here // as principal key property values - are in the correct order, which is the same order as the // key members themselves. // if (fkConstraint.FromProperties.Count == 1) { var singleKeyNameAndValue = keyPropAndValue.Single(); Debug.Assert(singleKeyNameAndValue.Item1 == fkConstraint.FromProperties[0].Name, "Unexpected single key property name"); principalKeyValues = new[] { singleKeyNameAndValue.Item2 }; } else { var keyValueMap = keyPropAndValue.ToDictionary(pav => pav.Item1, pav => pav.Item2, StringComparer.Ordinal); principalKeyValues = principalEntityType.KeyMemberNames.Select(memberName => keyValueMap[memberName]).ToList(); } // Create the ref to the principal entity based on the (now correctly ordered) key value expressions. // DbRefExpression principalRef = principalSetEnd.EntitySet.CreateRef(principalEntityType, principalKeyValues); DbRelatedEntityRef result = DbExpressionBuilder.CreateRelatedEntityRef(fkConstraint.ToRole, fkConstraint.FromRole, principalRef); return result; }
public override string WriteForeignKeyUpdateAction(ReferentialConstraint refConstraint) { return string.Empty; }