Skip to content

Commit

Permalink
Query: Use function mapping when querying for DbSet
Browse files Browse the repository at this point in the history
Resolves #20051
  • Loading branch information
smitpatel committed Jul 3, 2020
1 parent cb3f820 commit 3854154
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/EFCore.Relational/Metadata/Internal/StoreFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public StoreFunction([NotNull] DbFunction dbFunction, [NotNull] RelationalModel
/// 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 SortedDictionary<string, DbFunction> DbFunctions { get; }
public virtual SortedDictionary<string, DbFunction> DbFunctions { get; }

/// <inheritdoc />
public virtual bool IsBuiltIn { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
}

var entityType = tableValuedFunctionQueryRootExpression.EntityType;
var alias = (entityType.GetViewOrTableMappings().SingleOrDefault()?.Table.Name
?? entityType.ShortName()).Substring(0, 1).ToLower();
var alias = entityType.ShortName().Substring(0, 1).ToLower();

var translation = new TableValuedFunctionExpression(alias, function.Schema, function.Name, arguments);
var queryExpression = _sqlExpressionFactory.Select(entityType, translation);
Expand Down
28 changes: 27 additions & 1 deletion src/EFCore.Relational/Query/SqlExpressions/SelectExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,34 @@ internal SelectExpression(SqlExpression projection)
}

internal SelectExpression(IEntityType entityType)
: this(entityType, new TableExpression(entityType.GetViewOrTableMappings().Single().Table))
: base(null)
{
TableExpressionBase tableExpression;
var functionMappings = entityType.GetFunctionMappings();
if (functionMappings.Any())
{
var storeFunction = functionMappings.Single(e => e.IsDefaultFunctionMapping).Table;
var alias = entityType.ShortName().Substring(0, 1).ToLower();
tableExpression = new TableValuedFunctionExpression(
alias, storeFunction.Schema, storeFunction.Name, Array.Empty<SqlExpression>());
}
else
{
tableExpression = new TableExpression(entityType.GetViewOrTableMappings().Single().Table);
}

_tables.Add(tableExpression);

var entityProjection = new EntityProjectionExpression(entityType, tableExpression, false);
_projectionMapping[new ProjectionMember()] = entityProjection;

if (entityType.FindPrimaryKey() != null)
{
foreach (var property in entityType.FindPrimaryKey().Properties)
{
_identifier.Add((entityProjection.BindProperty(property), property.GetKeyValueComparer()));
}
}
}

internal SelectExpression(IEntityType entityType, TableExpressionBase tableExpression)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,31 @@ public class Address
public Customer Customer { get; set; }
}

public class OrderByYear
{
public int? CustomerId { get; set; }
public int? Count { get; set; }
public int? Year { get; set; }
}

public class MultProductOrders
{
public int OrderId { get; set; }

public Customer Customer { get; set; }
public int CustomerId { get; set; }

public DateTime OrderDate { get; set; }
}

public class TopSellingProduct
{
public Product Product { get; set; }
public int? ProductId { get; set; }

public int? AmountSold { get; set; }
}

protected class UDFSqlContext : PoolableDbContext
{
#region DbSets
Expand Down Expand Up @@ -152,36 +177,11 @@ public int AddValues(Expression<Func<int>> a, int b)

#region Queryable Functions

public class OrderByYear
{
public int? CustomerId { get; set; }
public int? Count { get; set; }
public int? Year { get; set; }
}

public class MultProductOrders
{
public int OrderId { get; set; }

public Customer Customer { get; set; }
public int CustomerId { get; set; }

public DateTime OrderDate { get; set; }
}

public IQueryable<OrderByYear> GetCustomerOrderCountByYear(int customerId)
{
return FromExpression(() => GetCustomerOrderCountByYear(customerId));
}

public class TopSellingProduct
{
public Product Product { get; set; }
public int? ProductId { get; set; }

public int? AmountSold { get; set; }
}

public IQueryable<TopSellingProduct> GetTopTwoSellingProducts()
{
return FromExpression(() => GetTopTwoSellingProducts());
Expand Down Expand Up @@ -255,7 +255,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
modelBuilder.HasDbFunction(typeof(UDFSqlContext).GetMethod(nameof(GetOrdersWithMultipleProducts)));

modelBuilder.Entity<OrderByYear>().HasNoKey();
modelBuilder.Entity<TopSellingProduct>().HasNoKey();
modelBuilder.Entity<TopSellingProduct>().HasNoKey().ToFunction("GetTopTwoSellingProducts");
}
}

Expand Down Expand Up @@ -1905,6 +1905,23 @@ orderby c.Id
}
}

[ConditionalFact]
public virtual void DbSet_mapped_to_function()
{
using (var context = CreateContext())
{
var products = (from t in context.Set<TopSellingProduct>()
orderby t.ProductId
select t).ToList();

Assert.Equal(2, products.Count);
Assert.Equal(3, products[0].ProductId);
Assert.Equal(249, products[0].AmountSold);
Assert.Equal(4, products[1].ProductId);
Assert.Equal(184, products[1].AmountSold);
}
}

#endregion

private void AssertTranslationFailed(Action testCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,16 @@ FROM [dbo].[GetOrdersWithMultipleProducts]([c].[Id]) AS [m]
ORDER BY [c].[Id], [t].[OrderId], [t].[Id]");
}

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

AssertSql(
@"SELECT [t].[AmountSold], [t].[ProductId]
FROM [dbo].[GetTopTwoSellingProducts]() AS [t]
ORDER BY [t].[ProductId]");
}

#endregion

public class SqlServer : UdfFixtureBase
Expand Down

0 comments on commit 3854154

Please sign in to comment.