Skip to content

Feature Request: Translate string.Join to LISTAGG #469

@lschloetterer

Description

@lschloetterer

Since EF Core 7 automatic translation from string.Join to STRING_AGG in MSSQL Server is supported.
Can a similar translation be supported by the Oracle provider to use LISTAGG?

Example Program:

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

[Table("EMP")]
internal class Employee
{
  [Key]
  [Column("EMPNO")]
  public int EmpNo { get; set; }
  [Column("ENAME")]
  public string Name { get; set; }
  [Column("JOB")]
  public string Job { get; set; }
  [Column("HIREDATE")]
  public DateTime HireDate { get; set; }
  [Column("DEPTNO")]
  public int DeptNo { get; set; }

  [ForeignKey(nameof(DeptNo))]
  public virtual Department Department { get; set; }
}

[Table("DEPT")]
internal class Department
{
  [Key]
  [Column("DEPTNO")]
  public int DeptNo { get; set; }
  [Column("DNAME")]
  public string Name { get; set; }
  [Column("LOC")]
  public string Location { get; set; }

  public virtual ICollection<Employee> Employees { get; set; }
}

internal class ReproContext : DbContext
{
  public DbSet<Department> Departments { get; set; }
  public DbSet<Employee> Employees { get; set; }

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {
    base.OnConfiguring(optionsBuilder);
    var connStr = "TODO";
    optionsBuilder.UseOracle(connStr, ora => ora.UseOracleSQLCompatibility(OracleSQLCompatibility.DatabaseVersion19));
  }
}

internal class Program
{
  public static async Task Main(string[] args)
  {
    var ctx = new ReproContext();
    var queryable = ctx.Departments
        .Where(d => d.Name == "RESEARCH")
        .Select(d => string.Join(',', d.Employees.OrderBy(e => e.Name).Select(e => e.Name)));
    Console.WriteLine(queryable.ToQueryString());
    var employeeNames = await queryable.SingleAsync();
    Console.WriteLine($"Result: {employeeNames}");
  }
}

The generated query is:

SELECT "d"."DEPTNO", "e"."ENAME", "e"."EMPNO"
FROM "DEPT" "d"
LEFT JOIN "EMP" "e" ON "d"."DEPTNO" = "e"."DEPTNO"
WHERE "d"."DNAME" = N'RESEARCH'
ORDER BY "d"."DEPTNO", "e"."ENAME"

Expected query would be:

SELECT LISTAGG("e"."ENAME", ',') WITHIN GROUP (ORDER BY "e"."ENAME")
FROM "DEPT" "d"
LEFT JOIN "EMP" "e" ON "d"."DEPTNO" = "e"."DEPTNO"
WHERE "d"."DNAME" = N'RESEARCH'

Related:
https://forums.oracle.com/ords/apexds/post/efcore-and-listagg-7389
dotnet/efcore#2981
dotnet/efcore#28110

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions