Closed subprime closed 2 years ago
@subprime The semantics of OfType
is "that type or any derived type", like is
or as
in C#. This is not an EF thing, but rather how OfType
is defined in LINQ.
That being said, I don't know the best way to get just entities of a specific type in EF Core. I tried:
context.Set<BaseVehicle>().Where(v => v.GetType() == typeof(Vehicle)).Cast<Vehicle>().ToList();
but that evaluates on the client. This:
context.Set<BaseVehicle>().Where(v => EF.Property<string>(v, "Discriminator") == nameof(Vehicle)).Cast<Vehicle>().ToList();
works, but it's a bit obscure.
@smitpatel Can you advise?
Hey @ajcvickers thanks for the fast reply. I know what you mean but it's wierd. My interpretion of OfType was to get the concrete type instead of the derived types because they have different endpoints in my api... 👎
@subprime Can you be more specific about what is weird about it? This is the way OfType
is defined in the base class libraries for .NET. If you feel this is wrong, then probably the compiler team is the best place to give that feedback.
@subprime - Please post your query.
@smitpatel Not sure which query you want, but here are the three I tested, with the repro code below.
Using OfType
:
context.Set<BaseVehicle>().OfType<Vehicle>()
SELECT [b].[Id], [b].[Discriminator], [b].[VehicleIdentificationNumber], [b].[PressReleaseAt]
FROM [BaseVehicle] AS [b]
WHERE [b].[Discriminator] IN (N'VehiclePrototype', N'Vehicle')
Using GetType
:
context.Set<BaseVehicle>()
.Where(v => v.GetType() == typeof(Vehicle)).Cast<Vehicle>()
SELECT [v].[Id], [v].[Discriminator], [v].[VehicleIdentificationNumber], [v].[PressReleaseAt]
FROM [BaseVehicle] AS [v]
WHERE [v].[Discriminator] IN (N'VehiclePrototype', N'Vehicle')
Using discriminator:
context.Set<BaseVehicle>()
.Where(v => EF.Property<string>(v, "Discriminator") == nameof(Vehicle)).Cast<Vehicle>()
SELECT [v].[Id], [v].[Discriminator], [v].[VehicleIdentificationNumber], [v].[PressReleaseAt]
FROM [BaseVehicle] AS [v]
WHERE [v].[Discriminator] IN (N'VehiclePrototype', N'Vehicle') AND ([v].[Discriminator] = N'Vehicle')
Full code:
public abstract class BaseVehicle
{
public int Id { get; set; }
}
public class Vehicle : BaseVehicle
{
public string VehicleIdentificationNumber { get; set; }
}
public class VehiclePrototype : Vehicle
{
public DateTimeOffset? PressReleaseAt { get; set; }
}
public class BloggingContext : DbContext
{
private static readonly LoggerFactory Logger
= new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseLoggerFactory(Logger)
.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Test;ConnectRetryCount=0");
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BaseVehicle>();
modelBuilder.Entity<Vehicle>();
modelBuilder.Entity<VehiclePrototype>();
}
}
public class Program
{
public static async Task Main()
{
using (var context = new BloggingContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Add(new Vehicle());
context.Add(new VehiclePrototype());
context.SaveChanges();
}
using (var context = new BloggingContext())
{
var vehicles = context.Set<BaseVehicle>().Where(v => v.GetType() == typeof(Vehicle)).Cast<Vehicle>().ToList();
}
}
}
@smitpatel which query you want?
In my queries i want achive that all vehicles except the prototype vehicles are returned
OfType
is certainly not the linq operator which maps to that behavior. Hence, I am having hard time understanding what is exact linq query you are running which uses OfType
and pulls all data which you don't want.
Posting your original attempted query and description would help us get you in write direction about what query should be written to work efficiently with EF.
Triage decision: v.GetType() == typeof(Vehicle)
should get converted to discriminator predicate when used with TPH mapping.
@smitpatel, sorry i was in holiday... Can you shortly explain what this means?
v.GetType() == typeof(Vehicle) should get converted to discriminator predicate when used with TPH mapping.
We will convert v.Getype() == typeof(Vehicle)
to EF.Property(v, "Discriminator) == "Vehicle"
automatically to do server evaluation.
Are there any plans to convert GetType()
in a select query? To allow querying only the type of a given TPH entity. It should be fairly simple.
@Xriuk using GetType() in queries works - this is what this issue is about. If something isn't working for you, please open a new issue with a minimal, runnable code sample that shows what you're trying to do.
In my queries i want achive that all vehicles except the prototype vehicles are returned, which has more properties. The query is build with OfType() but it seems that this has no influence of the behaviour.
Is this normal? What is the right way to filtrer the entities?
Further technical details
EF Core version: 2.1 Database Provider: Microsoft.EntityFrameworkCore.SqlServer Operating system: Windows 10 IDE: Visual Studio 2017 Pro 15.8.4