oracle / oracle/dotnet-db-samples

Feature Request: Translate string.Join to LISTAGG

Open
#469 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C#
Stars
434
Forks
191
Avg merge
1d 15h
Merged PRs (30d)
1

Description

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
https://github.com/dotnet/efcore/issues/2981
https://github.com/dotnet/efcore/pull/28110

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the ReproContext query using UseOracle and compare its generated SQL with the expected LISTAGG query in the issue. Trace how the Oracle provider handles string.Join, ordering, grouping, and aggregate translation; done means the example produces LISTAGG with the requested separator and ORDER BY semantics.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp, sql
Domain
backend, databases
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.