efcore icon indicating copy to clipboard operation
efcore copied to clipboard

Map EntityType to IQueryable

Open Materix opened this issue 2 years ago • 1 comments

I have simple model with statistics. I would like to calculate statistics on the fly using provided IQueryable. I could use ToSqlQuery but I'm worried about column and table naming. Actually there is ToQuery method but it's deprecated and does not attach instance to navigation property (even with correct SQL).

Model

public class Car
{
    public int CarId { get; set; }
    public CarStatistics CarStatistics { get; set; }
}


public class CarStatistics
{
    public int CarId { get; set; }
    public int Mileage { get; set; }
}

public class Ride
{
    public int RideId { get; set; }
    public int CarId { get; set; }
    public int Distance { get; set; }
}

Model Definition:

modelBuilder.Entity<Car>();
modelBuilder.Entity<Ride>();
modelBuilder.Entity<CarStatistics>(c =>
{
    c.HasKey(x => x.CarId);
    c.ToQuery(() => Set<Ride>().GroupBy(x => x.CarId).Select(g => new CarStatistics { CarId = g.Key, Mileage = g.Select(x => x.Distance).Sum() }));
});

and then use it as:

var query = context.Set<Car>().Include(x => x.CarStatistics).Take(1);
var car = query.ToList(); // <- there is no instance of CarStatistics in Car

Why there is no instance attached:

dbug: Microsoft.EntityFrameworkCore.Query[10107]
      Generated query execution expression:
      'queryContext => new SingleQueryingEnumerable<Car>(
          (RelationalQueryContext)queryContext,
          RelationalCommandCache.QueryExpression(
              Client Projections:
                  0 -> Dictionary<IProperty, int> { [Property: Car.CarId (int) Required PK AfterSave:Throw ValueGenerated.OnAdd, 0] }
strange -->>      1 -> 1 
strange -->>      2 -> 2
              SELECT t.CarId, t0.CarId, t0.Mileage
              FROM
              (
                  SELECT TOP(@__p_0) c.CarId
                  FROM Car AS c
              ) AS t
              LEFT JOIN
              (
                  SELECT r.CarId, SUM(r.Distance) AS Mileage
                  FROM Ride AS r
                  GROUP BY r.CarId
              ) AS t0 ON t.CarId == t0.CarId),
          null,
          Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, Car>,
          OemIq.RepairProcedures.Data.Contexts.RepairProceduresContext,
          False,
          False,
          True
      )'

EF Core version: 7.0 Database provider: Microsoft.EntityFrameworkCore.SqlServer

Materix avatar Jan 26 '23 07:01 Materix

Related to #20339, although in this case the request is for an entity type to be mapped to a LINQ query rooted on some other set, and that query to be used anywhere the entity type is, including navigations.

ajcvickers avatar Jan 26 '23 12:01 ajcvickers