Skip to content

Commit

Permalink
Project correct value types into array
Browse files Browse the repository at this point in the history
Issue #6337

The expression tree has converts in it to box the returned values. But this means we always ask for object from the reader. Therefore, use the value inside the convert when asking for the value from the data reader.
  • Loading branch information
ajcvickers committed Aug 20, 2016
1 parent bbd1745 commit 6328ca9
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,11 @@ public virtual IEnumerable<Type> GetProjectionTypes()
if (_projection.Any()
|| !IsProjectStar)
{
return _projection.Select(e => e.Type);
return _projection.Select(e =>
e.NodeType == ExpressionType.Convert
&& e.Type == typeof(object)
? ((UnaryExpression)e).Operand.Type
: e.Type);
}

return _tables.OfType<SelectExpression>().SelectMany(e => e.GetProjectionTypes());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,44 @@ public virtual void Where_subquery_closure_via_query_cache()
}
}

[ConditionalFact]
public virtual void Project_to_object_array()
{
AssertQuery<Employee>(
es => es.Where(e => e.EmployeeID == 1)
.Select(e => new object[] { e.EmployeeID, e.ReportsTo, EF.Property<string>(e, "Title") }),
entryCount: 0,
asserter: (e, a) => AssertArrays<object>(e, a, 3));
}

private static void AssertArrays<T>(IList<object> e, IList<object> a, int count)
{
Assert.Equal(1, e.Count);
Assert.Equal(1, a.Count);

var expectedArray = (T[])e[0];
var actualArray = (T[])a[0];

Assert.Equal(count, expectedArray.Length);
Assert.Equal(count, actualArray.Length);

for (var i = 0; i < expectedArray.Length; i++)
{
Assert.Same(expectedArray[i].GetType(), actualArray[i].GetType());
Assert.Equal(expectedArray[i], actualArray[i]);
}
}

[ConditionalFact]
public virtual void Project_to_int_array()
{
AssertQuery<Employee>(
es => es.Where(e => e.EmployeeID == 1)
.Select(e => new[] { e.EmployeeID, e.ReportsTo }),
entryCount: 0,
asserter: (e, a) => AssertArrays<int?>(e, a, 2));
}

[ConditionalFact]
public virtual void Where_simple_shadow()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,28 @@ public QuerySqlServerTest(NorthwindQuerySqlServerFixture fixture, ITestOutputHel
//TestSqlLoggerFactory.CaptureOutput(testOutputHelper);
}

public override void Project_to_object_array()
{
base.Project_to_object_array();

Assert.Equal(
@"SELECT [e].[EmployeeID], [e].[ReportsTo], [e].[Title]
FROM [Employees] AS [e]
WHERE [e].[EmployeeID] = 1",
Sql);
}

public override void Project_to_int_array()
{
base.Project_to_int_array();

Assert.Equal(
@"SELECT [e].[EmployeeID], [e].[ReportsTo]
FROM [Employees] AS [e]
WHERE [e].[EmployeeID] = 1",
Sql);
}

public override void Local_array()
{
base.Local_array();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,6 @@ public OptimisticConcurrencySqliteTest(F1SqliteFixture fixture)
{
}

// Disabled due to Issue #6337
public override void Calling_Reload_on_a_Unchanged_entity_makes_the_entity_unchanged()
{
}

// Disabled due to Issue #6337
public override void Calling_Reload_on_a_Modified_entity_makes_the_entity_unchanged()
{
}

// Disabled due to Issue #6337
public override void Calling_Reload_on_a_Deleted_entity_makes_the_entity_unchanged()
{
}

// Override failing tests because SQLite does not allow store-generated row versions.
// Row version behavior could be imitated on SQLite. See Issue #2195
public override Task Simple_concurrency_exception_can_be_resolved_with_store_values() => Task.FromResult(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.Specification.Tests;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -16,32 +15,6 @@ public PropertyValuesSqliteTest(PropertyValuesSqliteFixture fixture)
{
}

// Disabled due to Issue #6337
public override Task Scalar_store_values_of_a_derived_object_can_be_accessed_as_a_property_dictionary() => Task.FromResult(true);
public override Task Scalar_store_values_of_a_derived_object_can_be_accessed_asynchronously_as_a_property_dictionary() => Task.FromResult(true);
public override Task Store_values_can_be_copied_into_a_cloned_dictionary() => Task.FromResult(true);
public override Task Store_values_can_be_copied_into_a_cloned_dictionary_asynchronously() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_as_a_property_dictionary_using_IProperty() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_asynchronously_as_a_property_dictionary_using_IProperty() => Task.FromResult(true);
public override Task Scalar_store_values_of_a_derived_object_can_be_accessed_as_a_non_generic_property_dictionary() => Task.FromResult(true);
public override Task Scalar_store_values_of_a_derived_object_can_be_accessed_asynchronously_as_a_non_generic_property_dictionary() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_as_a_non_generic_property_dictionary() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_asynchronously_as_a_non_generic_property_dictionary() => Task.FromResult(true);
public override Task Store_values_really_are_store_values_not_current_or_original_values() => Task.FromResult(true);
public override Task Store_values_really_are_store_values_not_current_or_original_values_async() => Task.FromResult(true);
public override Task Store_values_can_be_copied_into_an_object() => Task.FromResult(true);
public override Task Store_values_can_be_copied_into_an_object_asynchronously() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_as_a_non_generic_property_dictionary_using_IProperty() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_asynchronously_as_a_non_generic_property_dictionary_using_IProperty() => Task.FromResult(true);
public override Task Store_values_for_derived_object_can_be_copied_into_an_object() => Task.FromResult(true);
public override Task Store_values_for_derived_object_can_be_copied_into_an_object_asynchronously() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_as_a_property_dictionary() => Task.FromResult(true);
public override Task Scalar_store_values_can_be_accessed_asynchronously_as_a_property_dictionary() => Task.FromResult(true);
public override Task Store_values_can_be_copied_into_a_non_generic_cloned_dictionary() => Task.FromResult(true);
public override Task Store_values_can_be_copied_asynchronously_into_a_non_generic_cloned_dictionary() => Task.FromResult(true);
public override Task Store_values_can_be_copied_non_generic_property_dictionary_into_an_object() => Task.FromResult(true);
public override Task Store_values_can_be_copied_asynchronously_non_generic_property_dictionary_into_an_object() => Task.FromResult(true);

public class PropertyValuesSqliteFixture : PropertyValuesFixtureBase
{
private const string DatabaseName = "PropertyValues";
Expand Down

0 comments on commit 6328ca9

Please sign in to comment.