From the course: .NET Essentials: LINQ for Databases

Explore the relevant LINQ types - .NET Tutorial

From the course: .NET Essentials: LINQ for Databases

Start my 1-month free trial

Explore the relevant LINQ types

- [Instructor] LINQ to Objects and LINQ to Entity Framework have similar query syntax. Where they differ is in what types are queryable. With LINQ to Objects, we can query any type that implements IEnumerable of T. With LINQ to Entity Framework, we can query any type that implements IQueryable of T. Here's a class diagram. We can explore the two interfaces. Note how IQueryable of T, shown at top center, inherits from IEnumerable of T. That means we can use familiar syntax, like a for each loop, to iterate the contents of the IQueryable of T type. It also implements IQueryable, the non-generic interface, which we'll talk about soon. Now, of course, we need concrete types that implement these interfaces. On the bottom left, I have shown list of T, which implements IEnumerable of T. This is the traditional example we see in LINQ to Objects code samples. On the bottom right is the DbSet of T class, which implements IQueryable of T. LINQ to Entity Framework utilizes the DbSet class. When you have an Entity Framework model, it is implemented as a DbSet. Why have another interface type? The answer to this question has to do with the source of the data. Ultimately, the data we want to query resides in a database. To build a responsive API, the LINQ had to consider how to work with this kind of data. Querying with LINQ to Objects against a list of T sorts is efficient. The list is in the application's local memory. But that's not the situation with databases where the information does not reside in app local memory. In fact, it's in another process, which could exist on a network server or in the cloud. What problems arise when working in a remote process? Experience teaches us that frequent requests to the database server is inefficient. Another principle, it is wasteful to pull all table rows to a local client. Usually, we want to get the minimum amount of data necessary to satisfy the query. Also, we want to take advantage of the power of the database engine. For example, it would be foolish for LINQ to reinvent all the features available in SQL Server. To support these different goals, LINQ has concepts that enable the scenario. They are query providers, expression trees and queryable sequences. Here's a picture to help. We write the LINQ query in our application. Our intent is to work with data in SQL Server or through some Entity Framework models. Rather than working directly with those sources, we rely on LINQ to help us do that work. Sure, we could dust off our skills with SQL but in many cases, we've already got data experts fine tuning the database store procedures and the data views or building our data models. We can stay in our code world, yet utilize the work of our data experts. We write our LINQ query and it is converted to an expression tree, which is a coded representation of our query actions and intent. An expression tree represents what you want to do, not how you want to do it. Remember, it's the database that does the work. A query provider understands how to morph the expression tree into specific instructions for the database. When the query is executed, the query provider interacts with the data source. It uses the expression to perform the query operations. The results returned from the database query are stored in a query sequence, which we can use in our application code. The query provider is software written specifically for one type of resource or database. The query provider interprets our query or rather it coverts the expression tree into efficient domain instructions for the underlying provider. Microsoft has written some providers. It is also extensible by other developers through the IQueryProvider interface. LINQ query syntax stays the same, no matter which provider we use because the provider knows what to do with the expression tree. The IQueryable interface is the way the provider and expression are bundled together. Let's revisit the IQueryable interface shown on the right. There are two properties of note. The provider property contains the LINQ provider and the expression property contains the expression tree. When you run the query, the interface contains the provider and expression everything it needs to communicate our query intent to the real data store.

Contents