C# tutorials > Language Integrated Query (LINQ) > LINQ to Entities (Entity Framework Core) > Introduction to LINQ to Entities

Introduction to LINQ to Entities

LINQ to Entities allows you to use LINQ (Language Integrated Query) to query data stored in a database through Entity Framework Core. This provides a strongly-typed and more readable way to interact with your database compared to traditional ADO.NET.

This tutorial will cover the fundamental concepts, syntax, and usage patterns of LINQ to Entities within the context of Entity Framework Core.

Setting up the Database Context

First, we need to define our database context. This context represents a session with the database and allows us to query and save data. Here's a basic example:

  • BloggingContext: Our derived DbContext class.
  • DbSet Blogs: Represents the table of Blogs in the database. DbSet Posts: Represents the table of Posts in the database.
  • Blog and Post: Our entity classes, representing database tables. The properties represent columns. Foreign key relationships are defined as well.

using Microsoft.EntityFrameworkCore;

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options) : base(options)
    {
    }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Basic LINQ Query

This demonstrates a simple LINQ query to retrieve all blogs from the database.

  • context.Blogs: Provides access to the Blogs DbSet.
  • .ToList(): Executes the query and retrieves the results as a List of Blog objects.

Important: The ToList() method executes the query against the database and materializes the results into memory. Avoid using it unnecessarily on large datasets.

using (var context = new BloggingContext(options))
{
    var blogs = context.Blogs.ToList();

    foreach (var blog in blogs)
    {
        Console.WriteLine(blog.Url);
    }
}

Filtering with LINQ

The Where clause allows you to filter the results based on a condition.

  • .Where(b => b.Url.Contains("example")): Filters the blogs to only include those where the URL contains "example".

using (var context = new BloggingContext(options))
{
    var blogs = context.Blogs
        .Where(b => b.Url.Contains("example"))
        .ToList();

    foreach (var blog in blogs)
    {
        Console.WriteLine(blog.Url);
    }
}

Ordering Results

The OrderBy clause sorts the results based on a specified property.

  • .OrderBy(b => b.Url): Sorts the blogs by the URL in ascending order. Use OrderByDescending for descending order.

using (var context = new BloggingContext(options))
{
    var blogs = context.Blogs
        .OrderBy(b => b.Url)
        .ToList();

    foreach (var blog in blogs)
    {
        Console.WriteLine(blog.Url);
    }
}

Selecting Specific Properties

The Select clause projects the results into a different form.

  • .Select(b => b.Url): Selects only the URL property from each blog object, resulting in a list of strings (URLs).

using (var context = new BloggingContext(options))
{
    var blogUrls = context.Blogs
        .Select(b => b.Url)
        .ToList();

    foreach (var url in blogUrls)
    {
        Console.WriteLine(url);
    }
}

Joining Tables

LINQ to Entities supports joins to combine data from multiple tables.

  • This example demonstrates an inner join between the Blogs and Posts tables based on the BlogId.
  • The result is a collection of anonymous objects containing the BlogUrl and PostTitle.

using (var context = new BloggingContext(options))
{
    var query = from b in context.Blogs
                join p in context.Posts on b.BlogId equals p.BlogId
                select new
                {
                    BlogUrl = b.Url,
                    PostTitle = p.Title
                };

    foreach (var result in query)
    {
        Console.WriteLine($"Blog: {result.BlogUrl}, Post: {result.PostTitle}");
    }
}

Concepts Behind the Snippets

The key concept is the translation of LINQ queries into SQL queries that the database can understand and execute. Entity Framework Core handles this translation behind the scenes. This allows you to write code that is more object-oriented and less database-specific.

Real-Life Use Case Section

Imagine building a blog application. You need to display a list of all blog posts by a specific author. LINQ to Entities makes this easy: You could use a Where clause to filter posts by author ID and then order them by date.

Best Practices

  • Avoid SELECT N+1 problem: Eager load related entities using Include() when you know you'll need them.
  • Use `AsNoTracking()` for read-only queries: This improves performance by disabling change tracking.
  • Optimize queries with indexes: Ensure your database tables have appropriate indexes for common query patterns.

Interview Tip

Be prepared to explain how LINQ queries are translated to SQL and the implications for performance. Understanding the difference between deferred execution and immediate execution (e.g., using ToList()) is crucial.

When to use them

LINQ to Entities is ideal when you need to interact with data stored in a relational database from your C# application. It simplifies data access and improves code readability.

Memory footprint

Be mindful of the memory footprint of your queries, especially when dealing with large datasets. Use pagination or other techniques to limit the amount of data loaded into memory at once. Avoid using ToList() unnecessarily.

Alternatives

Alternatives to LINQ to Entities include:

  • Dapper: A micro-ORM that provides faster performance but requires writing more SQL.
  • Raw ADO.NET: Provides the most control but requires the most code.
  • Stored Procedures: Can offer performance benefits for complex queries.

Pros

  • Type safety: Reduces the risk of runtime errors.
  • Readability: LINQ syntax is more expressive and easier to understand than raw SQL.
  • Maintainability: Changes to the database schema are reflected in your code through strongly-typed entities.

Cons

  • Performance overhead: The translation of LINQ queries to SQL can introduce some performance overhead.
  • Complexity: Complex queries can be challenging to write and optimize.
  • Learning curve: Requires understanding of both LINQ and Entity Framework Core.

FAQ

  • What is the difference between `ToList()` and `AsEnumerable()`?

    `ToList()` executes the query against the database and loads the results into a list in memory. `AsEnumerable()` defers the execution to a later stage, allowing further LINQ operations to be performed on the client side. Use `AsEnumerable()` when you need to perform operations that are not supported by the database provider.

  • How do I prevent SQL injection attacks when using LINQ to Entities?

    LINQ to Entities automatically parameterizes queries, which prevents SQL injection attacks. You don't need to manually sanitize input when using LINQ to Entities correctly. However, avoid using string concatenation to build queries dynamically.

  • What is eager loading, and why is it important?

    Eager loading is a technique to load related entities in a single query using the Include() method. It's important to avoid the SELECT N+1 problem, where a separate query is executed for each related entity, leading to poor performance.