private static void SetForeignKeyProperties( InternalEntityEntry dependentEntry, InternalEntityEntry principalEntry, IForeignKey foreignKey, bool setModified, bool fromQuery) { var principalProperties = foreignKey.PrincipalKey.Properties; var dependentProperties = foreignKey.Properties; for (var i = 0; i < foreignKey.Properties.Count; i++) { var principalProperty = principalProperties[i]; var dependentProperty = dependentProperties[i]; var principalValue = principalEntry[principalProperty]; var dependentValue = dependentEntry[dependentProperty]; if (!PrincipalValueEqualsDependentValue(principalProperty, dependentValue, principalValue) || (dependentEntry.IsConceptualNull(dependentProperty) && principalValue != null)) { if (principalEntry.HasTemporaryValue(principalProperty)) { dependentEntry.SetTemporaryValue(dependentProperty, principalValue, setModified); } else { dependentEntry.SetProperty(dependentProperty, principalValue, fromQuery, setModified); } dependentEntry.StateManager.UpdateDependentMap(dependentEntry, foreignKey); dependentEntry.SetRelationshipSnapshotValue(dependentProperty, principalValue); } } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task <InternalEntityEntry> PropagateValueAsync( InternalEntityEntry entry, IProperty property, CancellationToken cancellationToken = default) { Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK"); var principalEntry = TryPropagateValue(entry, property); if (principalEntry == null && property.IsKey()) { var valueGenerator = TryGetValueGenerator(property); if (valueGenerator != null) { var value = await valueGenerator.NextAsync(new EntityEntry(entry), cancellationToken); if (valueGenerator.GeneratesTemporaryValues) { entry.SetTemporaryValue(property, value); } else { entry[property] = value; } } } return(principalEntry); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual InternalEntityEntry PropagateValue(InternalEntityEntry entry, IProperty property) { Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK"); var principalEntry = TryPropagateValue(entry, property); if (principalEntry == null && property.IsKey()) { var valueGenerator = TryGetValueGenerator(property); if (valueGenerator != null) { var value = valueGenerator.Next(new EntityEntry(entry)); if (valueGenerator.GeneratesTemporaryValues) { entry.SetTemporaryValue(property, value); } else { entry[property] = value; } } } return(principalEntry); }
private static InternalEntityEntry TryPropagateValue(InternalEntityEntry entry, IProperty property) { var entityType = entry.EntityType; var stateManager = entry.StateManager; foreach (var foreignKey in entityType.GetForeignKeys()) { for (var propertyIndex = 0; propertyIndex < foreignKey.Properties.Count; propertyIndex++) { if (property == foreignKey.Properties[propertyIndex]) { var principal = foreignKey.DependentToPrincipal == null ? null : entry[foreignKey.DependentToPrincipal]; InternalEntityEntry principalEntry = null; if (principal != null) { principalEntry = stateManager.GetOrCreateEntry(principal, foreignKey.PrincipalEntityType); } else if (foreignKey.PrincipalToDependent != null) { foreach (var danglerEntry in stateManager.GetRecordedReferrers(entry.Entity, clear: false)) { if (danglerEntry.Item1 == foreignKey.PrincipalToDependent) { principalEntry = danglerEntry.Item2; break; } } } if (principalEntry != null) { var principalProperty = foreignKey.PrincipalKey.Properties[propertyIndex]; var principalValue = principalEntry[principalProperty]; if (!principalProperty.ClrType.IsDefaultValue(principalValue)) { if (principalEntry.HasTemporaryValue(principalProperty)) { entry.SetTemporaryValue(property, principalValue); } else { entry[property] = principalValue; } return(principalEntry); } } break; } } } return(null); }
private static void SetGeneratedValue(InternalEntityEntry entry, IProperty property, object generatedValue, bool isTemporary) { if (generatedValue != null) { if (isTemporary) { entry.SetTemporaryValue(property, generatedValue); } else { entry[property] = generatedValue; } } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual async Task <InternalEntityEntry?> PropagateValueAsync( InternalEntityEntry entry, IProperty property, CancellationToken cancellationToken = default) { Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK"); var generationProperty = property.FindGenerationProperty(); var principalEntry = TryPropagateValue(entry, property, generationProperty); if (principalEntry == null && property.IsKey()) { var valueGenerator = TryGetValueGenerator( generationProperty, generationProperty == property ? entry.EntityType : generationProperty?.DeclaringEntityType); if (valueGenerator != null) { var value = await valueGenerator.NextAsync(new EntityEntry(entry), cancellationToken) .ConfigureAwait(false); if (valueGenerator.GeneratesTemporaryValues) { entry.SetTemporaryValue(property, value); } else { entry[property] = value; } if (!valueGenerator.GeneratesStableValues) { entry.MarkUnknown(property); } } } return(principalEntry); }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> public virtual InternalEntityEntry?PropagateValue(InternalEntityEntry entry, IProperty property) { Check.DebugAssert(property.IsForeignKey(), $"property {property} is not part of an FK"); var generationProperty = property.FindGenerationProperty(); var principalEntry = TryPropagateValue(entry, property, generationProperty); if (principalEntry == null && property.IsKey() && !property.IsForeignKeyToSelf()) { var valueGenerator = TryGetValueGenerator( generationProperty, generationProperty == property ? entry.EntityType : generationProperty?.DeclaringEntityType); if (valueGenerator != null) { var value = valueGenerator.Next(new EntityEntry(entry)); if (valueGenerator.GeneratesTemporaryValues) { entry.SetTemporaryValue(property, value); } else { entry[property] = value; } if (!valueGenerator.GeneratesStableValues) { entry.MarkUnknown(property); } } } return(principalEntry); }