diff --git a/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs index 39e156405a3..d09996dc4d5 100644 --- a/src/EFCore.Cosmos/Extensions/CosmosPropertyExtensions.cs +++ b/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; @@ -20,7 +21,27 @@ public static class CosmosPropertyExtensions /// The property name used when targeting Cosmos. 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; + } /// /// Sets the property name used when targeting Cosmos. diff --git a/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs index b2cdd34dbd9..1b84cc4827b 100644 --- a/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs +++ b/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs @@ -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 @@ -53,6 +55,7 @@ public static IServiceCollection AddEntityFrameworkCosmos([NotNull] this IServic .TryAdd() .TryAdd() .TryAdd() + .TryAdd() .TryAdd() .TryAdd() .TryAdd() diff --git a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs index 45bf36ab143..1faff545265 100644 --- a/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.cs @@ -4,6 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -187,18 +188,19 @@ private static readonly MethodInfo _getItemMethodInfo private static readonly MethodInfo _toObjectMethodInfo = typeof(CosmosProjectionBindingRemovingExpressionVisitor).GetTypeInfo().GetRuntimeMethods() .Single(mi => mi.Name == nameof(SafeToObject)); - private static readonly MethodInfo _isNullMethodInfo - = typeof(CosmosProjectionBindingRemovingExpressionVisitor).GetTypeInfo().GetRuntimeMethods() - .Single(mi => mi.Name == nameof(IsNull)); private readonly SelectExpression _selectExpression; private readonly ParameterExpression _jObjectParameter; private readonly bool _trackQueryResults; - private readonly IDictionary _materializationContextBindings - = new Dictionary(); + private readonly IDictionary _materializationContextBindings + = new Dictionary(); private readonly IDictionary _projectionBindings = new Dictionary(); + private readonly IDictionary _ownerMappings + = new Dictionary(); + private (IEntityType EntityType, ParameterExpression JObjectVariable) _ownerInfo; + private ParameterExpression _ordinalParameter; public CosmosProjectionBindingRemovingExpressionVisitor( SelectExpression selectExpression, @@ -231,32 +233,40 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) projectionExpression = ((UnaryExpression)convertExpression.Operand).Operand; } - Expression accessExpression; + Expression innerAccessExpression; if (projectionExpression is ObjectArrayProjectionExpression objectArrayProjectionExpression) { - accessExpression = objectArrayProjectionExpression.AccessExpression; + innerAccessExpression = objectArrayProjectionExpression.AccessExpression; _projectionBindings[objectArrayProjectionExpression] = parameterExpression; storeName ??= objectArrayProjectionExpression.Name; } else { var entityProjectionExpression = (EntityProjectionExpression)projectionExpression; - _projectionBindings[entityProjectionExpression.AccessExpression] = parameterExpression; + var accessExpression = entityProjectionExpression.AccessExpression; + _projectionBindings[accessExpression] = parameterExpression; storeName ??= entityProjectionExpression.Name; - switch (entityProjectionExpression.AccessExpression) + if (_ownerInfo.EntityType != null) + { + _ownerMappings[accessExpression] = _ownerInfo; + } + + switch (accessExpression) { case ObjectAccessExpression innerObjectAccessExpression: - accessExpression = innerObjectAccessExpression.AccessExpression; + innerAccessExpression = innerObjectAccessExpression.AccessExpression; break; case RootReferenceExpression _: - accessExpression = _jObjectParameter; + innerAccessExpression = _jObjectParameter; break; default: throw new InvalidOperationException(); } } - var valueExpression = CreateGetStoreValueExpression(accessExpression, storeName, parameterExpression.Type); + var valueExpression = CreateGetValueExpression(innerAccessExpression, storeName, parameterExpression.Type); + + valueExpression = InjectDebug(valueExpression, Expression.Constant(new ExpressionPrinter().Print(innerAccessExpression)), Expression.Constant(storeName)); return Expression.MakeBinary(ExpressionType.Assign, binaryExpression.Left, valueExpression); } @@ -277,8 +287,7 @@ protected override Expression VisitBinary(BinaryExpression binaryExpression) entityProjectionExpression = (EntityProjectionExpression)projection; } - _materializationContextBindings[parameterExpression] - = _projectionBindings[entityProjectionExpression.AccessExpression]; + _materializationContextBindings[parameterExpression] = entityProjectionExpression.AccessExpression; var updatedExpression = Expression.New(newExpression.Constructor, Expression.Constant(ValueBuffer.Empty), @@ -327,7 +336,7 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp readExpression = Expression.Convert(readExpression, typeof(object)); } - return readExpression; + return InjectDebug(readExpression, Expression.Constant(new ExpressionPrinter().Print(innerExpression)), Expression.Constant(property)); } return base.VisitMethodCall(methodCallExpression); @@ -341,7 +350,7 @@ protected override Expression VisitExtension(Expression extensionExpression) { var projection = GetProjection(projectionBindingExpression); - return CreateGetStoreValueExpression( + return CreateGetValueExpression( _jObjectParameter, projection.Alias, projectionBindingExpression.Type, (projection.Expression as SqlExpression)?.TypeMapping); @@ -364,12 +373,20 @@ protected override Expression VisitExtension(Expression extensionExpression) } var jArray = _projectionBindings[objectArrayProjection]; - var jObjectParameter = Expression.Parameter(typeof(JObject), jArray.Name + "object"); - var ordinalParameter = Expression.Parameter(typeof(int), "ordinal"); + var jObjectParameter = Expression.Parameter(typeof(JObject), jArray.Name + "Object"); + var ordinalParameter = Expression.Parameter(typeof(int), jArray.Name + "Ordinal"); _projectionBindings[objectArrayProjection.InnerProjection.AccessExpression] = jObjectParameter; + if (_ownerInfo.EntityType != null) + { + _ownerMappings[objectArrayProjection.InnerProjection.AccessExpression] = _ownerInfo; + } + var previousOrdinalParameter = _ordinalParameter; + _ordinalParameter = ordinalParameter; var innerShaper = Visit(collectionShaperExpression.InnerShaper); + _ordinalParameter = previousOrdinalParameter; + return Expression.Call( _selectMethodInfo.MakeGenericMethod(typeof(JObject), innerShaper.Type), Expression.Call( @@ -389,6 +406,7 @@ protected override Expression VisitExtension(Expression extensionExpression) // These are the expressions added by JObjectInjectingExpressionVisitor var jObjectBlock = (BlockExpression)Visit(includeExpression.EntityExpression); + var jObjectVariable = jObjectBlock.Variables.Single(v => v.Type == typeof(JObject)); var jObjectCondition = (ConditionalExpression)jObjectBlock.Expressions[jObjectBlock.Expressions.Count - 1]; var shaperBlock = (BlockExpression)jObjectCondition.IfFalse; @@ -407,7 +425,11 @@ protected override Expression VisitExtension(Expression extensionExpression) var fixup = GenerateFixup( includingClrType, relatedEntityClrType, navigation, inverseNavigation) .Compile(); + + var previousOwner = _ownerInfo; + _ownerInfo = (navigation.DeclaringEntityType, jObjectVariable); var navigationExpression = Visit(includeExpression.NavigationExpression); + _ownerInfo = previousOwner; shaperExpressions.Add(Expression.Call( includeMethod.MakeGenericMethod(includingClrType, relatedEntityClrType), @@ -601,13 +623,53 @@ private Expression CreateGetValueExpression( var storeName = property.GetCosmosPropertyName(); if (storeName.Length == 0) { + var entityType = property.DeclaringEntityType; + if (!entityType.IsDocumentRoot()) + { + var ownership = entityType.FindOwnership(); + + if (ownership != null + && !ownership.IsUnique + && property.IsPrimaryKey() + && !property.IsForeignKey() + && property.ClrType == typeof(int)) + { + return _ordinalParameter; + } + + var principalProperty = property.FindFirstPrincipal(); + if (principalProperty != null) + { + Expression ownerJObjectExpression = null; + if (_ownerMappings.TryGetValue(jObjectExpression, out var ownerInfo)) + { + Debug.Assert(principalProperty.DeclaringEntityType.IsAssignableFrom(ownerInfo.EntityType)); + + ownerJObjectExpression = ownerInfo.JObjectVariable; + } + else if (jObjectExpression is RootReferenceExpression rootReferenceExpression) + { + ownerJObjectExpression = rootReferenceExpression; + } + else if (jObjectExpression is ObjectAccessExpression objectAccessExpression) + { + ownerJObjectExpression = objectAccessExpression.AccessExpression; + } + + if (ownerJObjectExpression != null) + { + return CreateGetValueExpression(ownerJObjectExpression, principalProperty); + } + } + } + return Expression.Default(property.ClrType); } - return CreateGetStoreValueExpression(jObjectExpression, storeName, property.ClrType, property.GetTypeMapping()); + return CreateGetValueExpression(jObjectExpression, storeName, property.ClrType, property.GetTypeMapping()); } - private Expression CreateGetStoreValueExpression( + private Expression CreateGetValueExpression( Expression jObjectExpression, string storeName, Type clrType, @@ -620,20 +682,20 @@ private Expression CreateGetStoreValueExpression( } else if (jObjectExpression is RootReferenceExpression rootReferenceExpression) { - innerExpression = CreateGetStoreValueExpression( + innerExpression = CreateGetValueExpression( _jObjectParameter, rootReferenceExpression.Alias, typeof(JObject)); } else if (jObjectExpression is ObjectAccessExpression objectAccessExpression) { var innerAccessExpression = objectAccessExpression.AccessExpression; - innerExpression = CreateGetStoreValueExpression( + innerExpression = CreateGetValueExpression( innerAccessExpression, ((IAccessExpression)innerAccessExpression).Name, typeof(JObject)); } - var jTokenExpression = Expression.Call(innerExpression, _getItemMethodInfo, Expression.Constant(storeName)); - Expression valueExpression; + var jTokenExpression = CreateReadJTokenExpression(innerExpression, storeName); + Expression valueExpression; var converter = typeMapping?.Converter; if (converter != null) { @@ -654,15 +716,6 @@ private Expression CreateGetStoreValueExpression( valueExpression = ConvertJTokenToType(jTokenExpression, clrType); } - if (clrType.IsNullableType()) - { - valueExpression = - Expression.Condition( - Expression.Call(_isNullMethodInfo, jTokenExpression), - Expression.Default(valueExpression.Type), - valueExpression); - } - return valueExpression; } @@ -674,10 +727,24 @@ private static Expression ConvertJTokenToType(Expression jTokenExpression, Type jTokenExpression); private static T SafeToObject(JToken token) - => token == null ? default : token.ToObject(); + => token == null || token.Type == JTokenType.Null ? default : token.ToObject(); + + private static readonly MethodInfo _debugMethodInfo + = typeof(CosmosProjectionBindingRemovingExpressionVisitor).GetTypeInfo().GetRuntimeMethods() + .Single(mi => mi.Name == nameof(BreakPoint)); + + private static Expression InjectDebug(Expression expression, params Expression[] state) + => Expression.Call( + _debugMethodInfo.MakeGenericMethod(expression.Type), + expression, + Expression.NewArrayInit(typeof(object), + state.Select(s => Expression.Convert(s, typeof(object))))); - private static bool IsNull(JToken token) - => token == null || token.Type == JTokenType.Null; + private static T BreakPoint(T result, params object[] state) + { + Debugger.Break(); + return result; + } } private class QueryingEnumerable : IEnumerable diff --git a/src/EFCore.Cosmos/Query/Internal/ObjectAccessExpression.cs b/src/EFCore.Cosmos/Query/Internal/ObjectAccessExpression.cs index 6bb460e498a..e58db566b6e 100644 --- a/src/EFCore.Cosmos/Query/Internal/ObjectAccessExpression.cs +++ b/src/EFCore.Cosmos/Query/Internal/ObjectAccessExpression.cs @@ -35,6 +35,14 @@ public ObjectAccessExpression(INavigation navigation, Expression accessExpressio AccessExpression = accessExpression; } + /// + /// 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. + /// + public override ExpressionType NodeType => ExpressionType.Extension; + /// /// 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 diff --git a/src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs b/src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs index de846e0801b..8e4af21f01d 100644 --- a/src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs +++ b/src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs @@ -4,6 +4,7 @@ using System; using System.Threading; using System.Threading.Tasks; +using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.Cosmos.Metadata.Internal; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; @@ -55,7 +56,7 @@ public virtual bool EnsureCreated() { created |= _cosmosClient.CreateContainerIfNotExists( entityType.GetCosmosContainer(), - entityType.GetCosmosPartitionKeyStoreName()); + GetCosmosPartitionKeyStoreName(entityType)); } if (created) @@ -89,7 +90,7 @@ public virtual async Task EnsureCreatedAsync(CancellationToken cancellatio { created |= await _cosmosClient.CreateContainerIfNotExistsAsync( entityType.GetCosmosContainer(), - entityType.GetCosmosPartitionKeyStoreName(), + GetCosmosPartitionKeyStoreName(entityType), cancellationToken); } @@ -145,5 +146,21 @@ public virtual bool CanConnect() /// public virtual Task CanConnectAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException(); + + /// + /// Returns the store name of the property that is used to store the partition key. + /// + /// The entity type to get the partition key property name for. + /// The name of the partition key property. + private static string GetCosmosPartitionKeyStoreName([NotNull] IEntityType entityType) + { + var name = entityType.GetCosmosPartitionKeyPropertyName(); + if (name != null) + { + return entityType.FindProperty(name).GetCosmosPropertyName(); + } + + return CosmosClientWrapper.DefaultPartitionKey; + } } } diff --git a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs index 8ce1803bb31..ede3c39212a 100644 --- a/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs +++ b/src/EFCore.Cosmos/Update/Internal/DocumentSource.cs @@ -71,6 +71,10 @@ public virtual JObject CreateDocument(IUpdateEntry entry) { document[storeName] = ConvertPropertyValue(property, entry.GetCurrentValue(property)); } + else if (entry.HasTemporaryValue(property)) + { + ((InternalEntityEntry)entry)[property] = entry.GetCurrentValue(property); + } } foreach (var ownedNavigation in entry.EntityType.GetNavigations()) @@ -130,6 +134,10 @@ public virtual JObject UpdateDocument(JObject document, IUpdateEntry entry) document[storeName] = ConvertPropertyValue(property, entry.GetCurrentValue(property)); anyPropertyUpdated = true; } + else if (entry.HasTemporaryValue(property)) + { + ((InternalEntityEntry)entry)[property] = entry.GetCurrentValue(property); + } } } diff --git a/src/EFCore.Cosmos/ValueGeneration/Internal/CosmosValueGeneratorSelector.cs b/src/EFCore.Cosmos/ValueGeneration/Internal/CosmosValueGeneratorSelector.cs new file mode 100644 index 00000000000..fdef196d1c0 --- /dev/null +++ b/src/EFCore.Cosmos/ValueGeneration/Internal/CosmosValueGeneratorSelector.cs @@ -0,0 +1,31 @@ +// 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; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.ValueGeneration; +using Microsoft.EntityFrameworkCore.ValueGeneration.Internal; + +namespace Microsoft.EntityFrameworkCore.Cosmos.ValueGeneration.Internal +{ + public class CosmosValueGeneratorSelector : ValueGeneratorSelector + { + public CosmosValueGeneratorSelector(ValueGeneratorSelectorDependencies dependencies) + : base(dependencies) + { + } + + public override ValueGenerator Create(IProperty property, IEntityType entityType) + { + var type = property.ClrType.UnwrapNullableType().UnwrapEnumType(); + + if (property.GetCosmosPropertyName() == "" + && type == typeof(int)) + { + return new TemporaryIntValueGenerator(); + } + + return base.Create(property, entityType); + } + } +} diff --git a/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs b/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs index 68fe75bc8de..b0c3d7cc17d 100644 --- a/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs +++ b/src/EFCore.Cosmos/ValueGeneration/Internal/IdValueGenerator.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Linq; using System.Text; -using JetBrains.Annotations; using Microsoft.EntityFrameworkCore.ChangeTracking; using Microsoft.EntityFrameworkCore.Cosmos.Storage.Internal; using Microsoft.EntityFrameworkCore.ValueGeneration; diff --git a/src/EFCore.Relational/Query/Internal/FromSqlParameterApplyingExpressionVisitor.cs b/src/EFCore.Relational/Query/Internal/FromSqlParameterApplyingExpressionVisitor.cs index 2a651205d30..9fa72e0f1df 100644 --- a/src/EFCore.Relational/Query/Internal/FromSqlParameterApplyingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Internal/FromSqlParameterApplyingExpressionVisitor.cs @@ -19,16 +19,16 @@ private class FromSqlParameterApplyingExpressionVisitor : ExpressionVisitor private readonly IDictionary _visitedFromSqlExpressions = new Dictionary(ReferenceEqualityComparer.Instance); - private readonly ISqlExpressionFactory _SqlExpressionFactory; + private readonly ISqlExpressionFactory _sqlExpressionFactory; private readonly ParameterNameGenerator _parameterNameGenerator; private readonly IReadOnlyDictionary _parametersValues; public FromSqlParameterApplyingExpressionVisitor( - ISqlExpressionFactory _sqlExpressionFactory, + ISqlExpressionFactory sqlExpressionFactory, ParameterNameGenerator parameterNameGenerator, IReadOnlyDictionary parametersValues) { - _SqlExpressionFactory = _sqlExpressionFactory; + _sqlExpressionFactory = sqlExpressionFactory; _parameterNameGenerator = parameterNameGenerator; _parametersValues = parametersValues; } @@ -67,7 +67,7 @@ public override Expression Visit(Expression expression) new TypeMappedRelationalParameter( parameterName, parameterName, - _SqlExpressionFactory.GetTypeMappingForValue(parameterValues[i]), + _sqlExpressionFactory.GetTypeMappingForValue(parameterValues[i]), parameterValues[i]?.GetType().IsNullableType())); } } diff --git a/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs b/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs index c734ffce4d5..c76120f07bd 100644 --- a/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs +++ b/src/EFCore.Relational/Query/Internal/ParameterValueBasedSelectExpressionOptimizer.cs @@ -32,7 +32,6 @@ public SelectExpression Optimize(SelectExpression selectExpression, IReadOnlyDic _parameterNameGeneratorFactory.Create(), parametersValues).Visit(query); - return (SelectExpression)query; } } diff --git a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs index f9b214adcd3..e4fa084e736 100644 --- a/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/RelationalSqlTranslatingExpressionVisitor.cs @@ -5,6 +5,7 @@ using System.Diagnostics; using System.Linq; using System.Linq.Expressions; +using System.Reflection; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Internal; using Microsoft.EntityFrameworkCore.Metadata; @@ -86,7 +87,7 @@ public virtual SqlExpression TranslateAverage(Expression expression) return inputType == typeof(float) ? _sqlExpressionFactory.Convert( _sqlExpressionFactory.Function( - "AVG", new[] { sqlExpression }, typeof(double), null), + "AVG", new[] { sqlExpression }, typeof(double)), sqlExpression.Type, sqlExpression.TypeMapping) : (SqlExpression)_sqlExpressionFactory.Function( diff --git a/src/EFCore/Query/NavigationExpansion/Internal/NavigationExpansionHelpers.cs b/src/EFCore/Query/NavigationExpansion/Internal/NavigationExpansionHelpers.cs index e5e3ee3c91e..634652c860f 100644 --- a/src/EFCore/Query/NavigationExpansion/Internal/NavigationExpansionHelpers.cs +++ b/src/EFCore/Query/NavigationExpansion/Internal/NavigationExpansionHelpers.cs @@ -234,10 +234,7 @@ public static Expression CreateKeyAccessExpression( AnonymousObject.AnonymousObjectCtor, Expression.NewArrayInit( typeof(object), - properties - .Select(p => Expression.Convert(CreatePropertyExpression(target, p, addNullCheck), typeof(object))) - .Cast() - .ToArray())); + properties.Select(p => Expression.Convert(CreatePropertyExpression(target, p, addNullCheck), typeof(object))))); private static Expression CreatePropertyExpression(Expression target, IProperty property, bool addNullCheck) { diff --git a/test/EFCore.Cosmos.FunctionalTests/NestedDocumentsTest.cs b/test/EFCore.Cosmos.FunctionalTests/NestedDocumentsTest.cs index 264ea9982d0..3405be050ae 100644 --- a/test/EFCore.Cosmos.FunctionalTests/NestedDocumentsTest.cs +++ b/test/EFCore.Cosmos.FunctionalTests/NestedDocumentsTest.cs @@ -80,8 +80,7 @@ public virtual async Task Can_update_owner_with_dependents() } } - // #12086 - //[ConditionalFact] + [ConditionalFact] public virtual async Task Can_add_collection_dependent_to_owner() { await using (var testDatabase = CreateTestStore()) @@ -158,9 +157,8 @@ public virtual async Task Can_add_collection_dependent_to_owner() var json = context.Entry(people[1]).Property("__jObject").CurrentValue; var jsonAddress = (JObject)((JArray)json["Stored Addresses"])[0]; Assert.Equal("Second", jsonAddress[nameof(Address.Street)]); - // Uncomment when issue #13578 is fixed - //Assert.Equal(2, jsonAddress["unmappedId"]); - //Assert.Equal(2, jsonAddress.Count); + Assert.Equal(2, jsonAddress["unmappedId"]); + Assert.Equal(2, jsonAddress.Count); addresses = people[2].Addresses.ToList(); Assert.Equal(3, addresses.Count); @@ -192,8 +190,7 @@ public virtual async Task Can_query_just_nested_reference() } } - // #12086 - //[ConditionalFact] + [ConditionalFact] public virtual async Task Can_query_just_nested_collection() { await using (var testDatabase = CreateTestStore()) diff --git a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs index 03847fdb35c..f459f300d04 100644 --- a/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/BuiltInDataTypesSqlServerTest.cs @@ -11,7 +11,6 @@ using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.TestUtilities; -using Microsoft.EntityFrameworkCore.TestUtilities.Xunit; using Xunit; using Xunit.Abstractions;