Skip to content

Commit

Permalink
Don't persist keys for embedded entities
Browse files Browse the repository at this point in the history
Fixes #13578
Part of #12086
  • Loading branch information
AndriySvyryd committed Jul 27, 2019
1 parent b9653e8 commit d4d422b
Show file tree
Hide file tree
Showing 26 changed files with 394 additions and 377 deletions.
Expand Up @@ -23,7 +23,7 @@ public static class CosmosDbContextOptionsExtensions
/// <param name="accountEndpoint"> The account end-point to connect to. </param>
/// <param name="accountKey"> The account key. </param>
/// <param name="databaseName"> The database name. </param>
/// <param name="cosmosOptionsAction">An optional action to allow additional Cosmos-specific configuration.</param>
/// <param name="cosmosOptionsAction"> An optional action to allow additional Cosmos-specific configuration. </param>
/// <returns> The options builder so that further configuration can be chained. </returns>
public static DbContextOptionsBuilder<TContext> UseCosmos<TContext>(
[NotNull] this DbContextOptionsBuilder<TContext> optionsBuilder,
Expand All @@ -46,7 +46,7 @@ public static class CosmosDbContextOptionsExtensions
/// <param name="accountEndpoint"> The account end-point to connect to. </param>
/// <param name="accountKey"> The account key. </param>
/// <param name="databaseName"> The database name. </param>
/// <param name="cosmosOptionsAction">An optional action to allow additional Cosmos-specific configuration.</param>
/// <param name="cosmosOptionsAction"> An optional action to allow additional Cosmos-specific configuration. </param>
/// <returns> The options builder so that further configuration can be chained. </returns>
public static DbContextOptionsBuilder UseCosmos(
[NotNull] this DbContextOptionsBuilder optionsBuilder,
Expand Down
23 changes: 22 additions & 1 deletion src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs
@@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Linq;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Metadata;
Expand All @@ -20,7 +21,27 @@ public static class CosmosPropertyExtensions
/// <returns> The property name used when targeting Cosmos. </returns>
public static string GetCosmosPropertyName([NotNull] this IProperty property) =>
(string)property[CosmosAnnotationNames.PropertyName]
?? property.Name;
?? GetDefaultPropertyName(property);

private static string GetDefaultPropertyName(IProperty property)
{
var entityType = property.DeclaringEntityType;
var ownership = entityType.FindOwnership();

if (ownership != null
&& !entityType.IsDocumentRoot())
{
var pk = property.FindContainingPrimaryKey();
if (pk != null
&& pk.Properties.Count == ownership.Properties.Count + (ownership.IsUnique ? 0 : 1)
&& ownership.Properties.All(fkProperty => pk.Properties.Contains(fkProperty)))
{
return "";
}
}

return property.Name;
}

/// <summary>
/// Sets the property name used when targeting Cosmos.
Expand Down
Expand Up @@ -9,12 +9,14 @@
using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Conventions.Internal;
using Microsoft.EntityFrameworkCore.Cosmos.Query.Internal;
using Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal;
using Microsoft.EntityFrameworkCore.Cosmos.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Infrastructure;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.EntityFrameworkCore.ValueGeneration;

// ReSharper disable once CheckNamespace
namespace Microsoft.Extensions.DependencyInjection
Expand Down Expand Up @@ -53,6 +55,7 @@ public static IServiceCollection AddEntityFrameworkCosmos([NotNull] this IServic
.TryAdd<IDbContextTransactionManager, CosmosTransactionManager>()
.TryAdd<IModelValidator, CosmosModelValidator>()
.TryAdd<IProviderConventionSetBuilder, CosmosConventionSetBuilder>()
.TryAdd<IValueGeneratorSelector, CosmosValueGeneratorSelector>()
.TryAdd<IDatabaseCreator, CosmosDatabaseCreator>()
.TryAdd<IQueryContextFactory, CosmosQueryContextFactory>()
.TryAdd<ITypeMappingSource, CosmosTypeMappingSource>()
Expand Down
19 changes: 13 additions & 6 deletions src/EFCore.Cosmos/Metadata/Conventions/StoreKeyConvention.cs
Expand Up @@ -9,15 +9,16 @@
using Microsoft.EntityFrameworkCore.Utilities;
using Newtonsoft.Json.Linq;

// ReSharper disable once CheckNamespace
namespace Microsoft.EntityFrameworkCore.Metadata.Conventions
{
/// <summary>
/// <para>
/// A convention that adds the 'id' property - a key required by Azure Cosmos.
/// </para>
/// This convention also add the '__jObject' containing the JSON object returned by the store.
/// <para>
/// </para>
/// This convention also adds the '__jObject' containing the JSON object returned by the store.
/// </para>
/// </summary>
public class StoreKeyConvention :
IEntityTypeAddedConvention,
Expand Down Expand Up @@ -52,10 +53,6 @@ private static void Process(IConventionEntityTypeBuilder entityTypeBuilder)
var idProperty = entityTypeBuilder.Property(typeof(string), IdPropertyName);
idProperty.HasValueGenerator((_, __) => new IdValueGenerator());
entityTypeBuilder.HasKey(new[] { idProperty.Metadata });

var jObjectProperty = entityTypeBuilder.Property(typeof(JObject), JObjectPropertyName);
jObjectProperty.ToJsonProperty("");
jObjectProperty.ValueGenerated(ValueGenerated.OnAddOrUpdate);
}
else
{
Expand All @@ -68,7 +65,17 @@ private static void Process(IConventionEntityTypeBuilder entityTypeBuilder)
entityType.Builder.HasNoKey(key);
}
}
}

if (entityType.BaseType == null
&& !entityType.IsKeyless)
{
var jObjectProperty = entityTypeBuilder.Property(typeof(JObject), JObjectPropertyName);
jObjectProperty.ToJsonProperty("");
jObjectProperty.ValueGenerated(ValueGenerated.OnAddOrUpdate);
}
else
{
var jObjectProperty = entityType.FindDeclaredProperty(JObjectPropertyName);
if (jObjectProperty != null)
{
Expand Down
Expand Up @@ -200,7 +200,8 @@ protected override Expression VisitMember(MemberExpression memberExpression)
throw new InvalidOperationException();
}

var navigationProjection = innerEntityProjection.BindMember(memberExpression.Member, innerExpression.Type, out var propertyBase);
var navigationProjection = innerEntityProjection.BindMember(
memberExpression.Member, innerExpression.Type, clientEval: true, out var propertyBase);

if (!(propertyBase is INavigation navigation)
|| !navigation.IsEmbedded())
Expand Down

0 comments on commit d4d422b

Please sign in to comment.