Skip to content

Commit

Permalink
Throw when tracking an owned entity as the owned type its base is map…
Browse files Browse the repository at this point in the history
…ped to.

Remove unsupported Cosmos tests.
  • Loading branch information
AndriySvyryd committed Mar 11, 2019
1 parent ae73b02 commit 01a8766
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 249 deletions.
8 changes: 0 additions & 8 deletions src/EFCore.Cosmos/Properties/CosmosStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions src/EFCore.Cosmos/Properties/CosmosStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@
<data name="OrphanedNestedDocumentSensitive" xml:space="preserve">
<value>The entity of type '{entityType}' is mapped as a part of the document mapped to '{missingEntityType}', but there is no tracked entity of this type with the key value '{keyValue}'.</value>
</data>
<data name="QueryRootNestedEntityType" xml:space="preserve">
<value>The entity of type '{entityType}' cannot be queried directly because it is mapped as a part of the document mapped to '{principalEntityType}'. Rewrite the query to start with '{principalEntityType}'.</value>
</data>
<data name="UnableToDiscriminate" xml:space="preserve">
<value>No matching discriminator values where found for this instance of '{entityType}'.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Linq.Expressions;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Cosmos.Internal;
Expand Down Expand Up @@ -42,11 +43,7 @@ public CosmosEntityQueryableExpressionVisitor(
protected override Expression VisitEntityQueryable([NotNull] Type elementType)
{
var entityType = _model.FindEntityType(elementType);
if (!entityType.IsDocumentRoot())
{
throw new InvalidOperationException(
CosmosStrings.QueryRootNestedEntityType(entityType.DisplayName(), entityType.FindOwnership().PrincipalEntityType.DisplayName()));
}
Debug.Assert(entityType.IsDocumentRoot());

return new QueryShaperExpression(
QueryModelVisitor.QueryCompilationContext.IsAsyncQuery,
Expand Down
16 changes: 4 additions & 12 deletions src/EFCore/ChangeTracking/Internal/EntityEntryGraphIterator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,15 @@ public virtual void TraverseGraph<TState>(
{
foreach (var relatedEntity in ((IEnumerable)navigationValue).Cast<object>().ToList())
{
var targetEntry = targetEntityType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(relatedEntity, targetEntityType)
: stateManager.GetOrCreateEntry(relatedEntity);
var targetEntry = stateManager.GetOrCreateEntry(relatedEntity, targetEntityType);
TraverseGraph(
(EntityEntryGraphNode<TState>)node.CreateNode(node, targetEntry, navigation),
handleNode);
}
}
else
{
var targetEntry = targetEntityType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(navigationValue, targetEntityType)
: stateManager.GetOrCreateEntry(navigationValue);
var targetEntry = stateManager.GetOrCreateEntry(navigationValue, targetEntityType);
TraverseGraph(
(EntityEntryGraphNode<TState>)node.CreateNode(node, targetEntry, navigation),
handleNode);
Expand Down Expand Up @@ -103,9 +99,7 @@ public virtual async Task TraverseGraphAsync<TState>(
{
foreach (var relatedEntity in ((IEnumerable)navigationValue).Cast<object>().ToList())
{
var targetEntry = targetType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(relatedEntity, targetType)
: stateManager.GetOrCreateEntry(relatedEntity);
var targetEntry = stateManager.GetOrCreateEntry(relatedEntity, targetType);
await TraverseGraphAsync(
(EntityEntryGraphNode<TState>)node.CreateNode(node, targetEntry, navigation),
handleNode,
Expand All @@ -114,9 +108,7 @@ await TraverseGraphAsync(
}
else
{
var targetEntry = targetType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(navigationValue, targetType)
: stateManager.GetOrCreateEntry(navigationValue);
var targetEntry = stateManager.GetOrCreateEntry(navigationValue, targetType);
await TraverseGraphAsync(
(EntityEntryGraphNode<TState>)node.CreateNode(node, targetEntry, navigation),
handleNode,
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/Internal/IStateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ InternalEntityEntry StartTrackingFromQuery(
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
InternalEntityEntry TryGetEntry([NotNull] object entity, [NotNull] IEntityType type);
InternalEntityEntry TryGetEntry([NotNull] object entity, [NotNull] IEntityType type, bool throwOnTypeMismatch = true);

/// <summary>
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
Expand Down
2 changes: 1 addition & 1 deletion src/EFCore/ChangeTracking/Internal/KeyPropagator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private static InternalEntityEntry TryPropagateValue(InternalEntityEntry entry,
InternalEntityEntry principalEntry = null;
if (principal != null)
{
principalEntry = stateManager.GetOrCreateEntry(principal);
principalEntry = stateManager.GetOrCreateEntry(principal, foreignKey.PrincipalEntityType);
}
else if (foreignKey.PrincipalToDependent != null)
{
Expand Down
13 changes: 5 additions & 8 deletions src/EFCore/ChangeTracking/Internal/NavigationFixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public virtual void NavigationReferenceChanged(InternalEntityEntry entry, INavig

if (ReferenceEquals(victimDependentEntry[navigation], newTargetEntry.Entity)
&& victimDependentEntry.StateManager
.TryGetEntry(victimDependentEntry.Entity, targetEntityType) != null)
.TryGetEntry(victimDependentEntry.Entity, navigation.DeclaringEntityType) != null)
{
SetNavigation(victimDependentEntry, navigation, null);
}
Expand Down Expand Up @@ -185,9 +185,7 @@ public virtual void NavigationReferenceChanged(InternalEntityEntry entry, INavig
stateManager.RecordReferencedUntrackedEntity(newValue, navigation, entry);
entry.SetRelationshipSnapshotValue(navigation, newValue);

newTargetEntry = targetEntityType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(newValue, targetEntityType)
: stateManager.GetOrCreateEntry(newValue);
newTargetEntry = stateManager.GetOrCreateEntry(newValue, targetEntityType);

_attacher.AttachGraph(
newTargetEntry,
Expand Down Expand Up @@ -250,9 +248,7 @@ public virtual void NavigationCollectionChanged(

foreach (var newValue in added)
{
var newTargetEntry = targetEntityType.HasDefiningNavigation()
? stateManager.GetOrCreateEntry(newValue, targetEntityType)
: stateManager.GetOrCreateEntry(newValue);
var newTargetEntry = stateManager.GetOrCreateEntry(newValue, targetEntityType);

if (newTargetEntry.EntityState != EntityState.Detached)
{
Expand Down Expand Up @@ -364,7 +360,8 @@ var targetDependentEntry
ConditionallyNullForeignKeyProperties(targetDependentEntry, newPrincipalEntry, foreignKey);

if (ReferenceEquals(targetDependentEntry[dependentToPrincipal], newPrincipalEntry.Entity)
&& targetDependentEntry.StateManager.TryGetEntry(targetDependentEntry.Entity, foreignKey.DeclaringEntityType) != null)
&& targetDependentEntry.StateManager.TryGetEntry(
targetDependentEntry.Entity, foreignKey.DeclaringEntityType) != null)
{
SetNavigation(targetDependentEntry, dependentToPrincipal, null);
}
Expand Down
44 changes: 38 additions & 6 deletions src/EFCore/ChangeTracking/Internal/StateManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,22 @@ public virtual InternalEntityEntry GetOrCreateEntry(object entity, IEntityType e
{
_trackingQueryMode = TrackingQueryMode.Multiple;

var runtimeEntityType = _model.FindRuntimeEntityType(entity.GetType());
if (runtimeEntityType != null)
{
if (!entityType.IsAssignableFrom(runtimeEntityType))
{
throw new InvalidOperationException(CoreStrings.TrackingTypeMismatch(
runtimeEntityType.DisplayName(), entityType.DisplayName()));
}
entityType = runtimeEntityType;
}

if (entityType.FindPrimaryKey() == null)
{
throw new InvalidOperationException(CoreStrings.KeylessTypeTracked(entityType.DisplayName()));
}

entry = _internalEntityEntryFactory.Create(this, entityType, entity);

UpdateReferenceMaps(entry, EntityState.Detached, null);
Expand Down Expand Up @@ -354,10 +370,25 @@ public virtual InternalEntityEntry TryGetEntry(object entity, bool throwOnNonUni
/// This API supports the Entity Framework Core infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public virtual InternalEntityEntry TryGetEntry(object entity, IEntityType entityType)
=> _entityReferenceMap.TryGet(entity, entityType, out var entry, throwOnNonUniqueness: false)
? entry
: null;
public virtual InternalEntityEntry TryGetEntry(object entity, IEntityType entityType, bool throwOnTypeMismatch = true)
{
var found = _entityReferenceMap.TryGet(entity, entityType, out var entry, throwOnNonUniqueness: false);
if (found
&& !entityType.IsAssignableFrom(entry.EntityType))
{
if (throwOnTypeMismatch)
{
throw new InvalidOperationException(CoreStrings.TrackingTypeMismatch(
entry.EntityType.DisplayName(), entityType.DisplayName()));
}
else
{
return null;
}
}

return found ? entry : null;
}

private IIdentityMap GetOrCreateIdentityMap(IKey key)
{
Expand Down Expand Up @@ -749,14 +780,15 @@ public virtual IEnumerable<InternalEntityEntry> GetDependentsFromNavigation(Inte

if (foreignKey.IsUnique)
{
var dependentEntry = TryGetEntry(navigationValue);
var dependentEntry = TryGetEntry(navigationValue, foreignKey.DeclaringEntityType);

return dependentEntry != null
? new[] { dependentEntry }
: Enumerable.Empty<InternalEntityEntry>();
}

return ((IEnumerable<object>)navigationValue).Select(v => TryGetEntry(v)).Where(e => e != null);
return ((IEnumerable<object>)navigationValue)
.Select(v => TryGetEntry(v, foreignKey.DeclaringEntityType)).Where(e => e != null);
}

/// <summary>
Expand Down
8 changes: 8 additions & 0 deletions src/EFCore/Properties/CoreStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore/Properties/CoreStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1120,4 +1120,7 @@
<data name="DerivedEntityCannotBeKeyless" xml:space="preserve">
<value>Unable to set a base type for entity type '{entityType}' because it has been configured as having no keys.</value>
</data>
<data name="TrackingTypeMismatch" xml:space="preserve">
<value>The instance of entity type '{runtimeEntityType}' cannot be tracked as the entity type '{entityType}' because they are not in the same hierarchy.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -539,8 +539,8 @@ private static void SetRelationshipIsLoaded(
IPropertyBase navigation,
object entity)
=> stateManager
.TryGetEntry(entity, (IEntityType)navigation.DeclaringType)
.SetIsLoaded((INavigation)navigation);
.TryGetEntry(entity, (IEntityType)navigation.DeclaringType, throwOnTypeMismatch: false)
?.SetIsLoaded((INavigation)navigation);

private static readonly MethodInfo _setRelationshipIsLoadedNoTrackingMethodInfo
= typeof(IncludeLoadTreeNode).GetTypeInfo()
Expand Down
Loading

0 comments on commit 01a8766

Please sign in to comment.