Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Whats the difference between IQueryable and DbQuery?

Following up on this question/answer
How to make Entity Framework Data Context Readonly

The solution is to make your DbContext collections of the type DbQuery, but that is a rather specialized type (it's buried down in the namespaces for EF).

So, what's the functional difference between have a DbContext with this:

public DbQuery<Customer> Customers
{
    get { return Set<Customer>().AsNoTracking(); }
}

vs this:

public IQueryable<Customer> Customers
{
    get { return Set<Customer>().AsNoTracking(); }
}

...the EF documentation is very light when it comes to the DbQuery class, but I prefer the idea of having DbContext made up of interfaces rather than classes so I'd like to avoid it. What additional benefits does the DbQuery class provide?

Update

After reading the answers and just looking at the code I realized my question was a little silly. I was too quick to ask before I thought! Obviously the underlying concrete object will be a DbQuery regardless, so the actually inner functionality will be the same. It seems to me that using IQueryable is the better choice. Thanks for your patience!

like image 674
C.List Avatar asked Sep 29 '22 03:09

C.List


2 Answers

DBQuery is a non-generic LINQ to Entities query against a DbContext. Exposing this will give you LINQ functionality against Entities. If you don't need this, use the IQueryable interface abstraction.

IOrderedQueryable

Intended for implementation by query providers. This interface represents the result of a sorting query that calls the method(s) OrderBy, OrderByDescending, ThenBy or ThenByDescending. When CreateQuery is called and passed an expression tree that represents a sorting query, the resulting IQueryable object must be of a type that implements IOrderedQueryable.

IListSource 

Provides functionality to an object to return a list that can be bound to a data source.

IDbAsyncEnumerable

Asynchronous version of the IEnumerable interface that allows elements to be retrieved asynchronously. This interface is used to interact with Entity Framework queries and shouldn't be implemented by custom classes.

like image 168
Sievajet Avatar answered Oct 06 '22 19:10

Sievajet


This is an old question, but it comes up in a google search on DbQuery, so just to update things a bit:

In EF Core 2.1, QueryTypes are now mapped to DbQuery types, as described in the documentation located at

https://docs.microsoft.com/en-us/ef/core/modeling/query-types

Here are the relevant bits:

Query types have many similarities with entity types...

...

However they are different from entity types in that they:

  • Do not require a key to be defined.

  • Are never tracked for changes on the DbContext and therefore are never inserted, updated or deleted on the database.

  • Are never discovered by convention.

    • Only support a subset of navigation mapping capabilities - Specifically:
    • They may never act as the principal end of a relationship.
    • They can only contain reference navigation properties pointing to entities. Entities cannot contain navigation properties to query types.
  • Are addressed on the ModelBuilder using the Query method rather than the Entity method.

  • Are mapped on the DbContext through properties of type DbQuery rather than DbSet

  • Are mapped to database objects using the ToView method, rather than ToTable.

  • May be mapped to a defining query - A defining query is a secondary query declared in the model that acts a data source for a query type.

You define a QueryType in your DbContext like a DbSet, but using the DbQuery type:

public virtual DbQuery<CustomClassThatMapsYourQueryResults> QueryResults { get; set; }

Then in your OnModelCreating method you indicate that your custom results object is mapped to a stored proc in the database:

modelBuilder.Query<CustomClassThatMapsYourQueryResults>();

Then in your data access code somewhere:

var someVariable = 1;
var someOtherVariable = "someValue";

...

var myResults = _dbContext.FromSql($"spStoredProcName {someVariable} '{someOtherVariable}'"); 

As far as I know, the only way to populate the DbQuery< T > object is to use the FromSql() method. The DbQuery< T > results of the FromSql() method return IQueryable< T >.

like image 29
camainc Avatar answered Oct 06 '22 18:10

camainc