当前位置: 欣欣网 > 码农

深入了解 LINQ:关联数据查询实例讲解

2024-06-01码农

概述: 现在重点介绍利用 LINQ 查询数据库,特别是在处理各种模型关系(如一对一、一对多和多对多)时。本高级指南旨在填补资源缺口,并为您提供掌握这些概念的实用见解和代码示例。1. 了解数据库中的模型关系在深入研究 LINQ 查询之前,请务必了解数据库模型中的关系类型:一对一:表中的一条记录链接到另一个表中的一条记录,并且只有一条记录链 接。一对多:一个表中的记录可以与另一个表中的一个或多个记录相关联。多对多:一个表中的记录可以与另一个表中的多个记录相关联,反之亦然。为了说明 C# 中的各种关系,我们需要创建几个类来表示这些关系中涉及的实体。让我们为 、 、 、 、 、 和 中间类创建类,以演示一对一

现在重点介绍利用 LINQ 查询数据库,特别是在处理各种模型关系(如一对一、一对多和多对多)时。本高级指南旨在填补资源缺口,并为您提供掌握这些概念的实用见解和代码示例。

1. 了解数据库中的模型关系

在深入研究 LINQ 查询之前,请务必了解数据库模型中的关系类型:

一对一:表中的一条记录链接到另一个表中的一条记录,并且只有一条记录链> 接。 一对多:一个表中的记录可以与另一个表中的一个或多个记录相关联。 多对多:一个表中的记录可以与另一个表中的多个记录相关联,反之亦然。

为了说明 C# 中的各种关系,我们需要创建几个类来表示这些关系中涉及的实体。让我们为 、 、 、 、 、 和 中间类创建类,以演示一对一、一对多和多对多的关系。UserUserProfileCustomerOrderStudentCourseStudentCourse

一对一关系:用户和 UserProfile

public classUser
{
publicint ID { get; set; }
publicstring Name { get; set; }
publicUserProfile UserProfile { get; set; } // Navigation property for one-to-one relationship
}
public classUserProfile
{
publicint UserID { get; set; } // Primary key and also foreign key
publicstring ProfilePicture { get; set; }
publicUser User { get; set; } // Navigation property for one-to-one relationship
}

一对多关系:客户和订单

public classCustomer
{
publicint ID { get; set; }
publicstring Name { get; set; }
publicList<Order> Orders { get; set; } // Navigation property for one-to-many relationship
}
public classOrder
{
publicint OrderID { get; set; }
publicint CustomerID { get; set; } // Foreign key
publicdecimal TotalAmount { get; set; }
publicCustomer Customer { get; set; } // Navigation property for one-to-many relationship
}

多对多关系:学生、课程和 StudentCourse

public classStudent
{
publicint ID { get; set; }
publicstring Name { get; set; }
publicList<StudentCourse> StudentCourses { get; set; } // Navigation property for many-to-many relationship
}
public classCourse
{
publicint ID { get; set; }
publicstring CourseName { get; set; }
publicList<StudentCourse> StudentCourses { get; set; } // Navigation property for many-to-many relationship
}
public classStudentCourse
{
publicint StudentID { get; set; } // Composite key (StudentID, CourseID)
publicint CourseID { get; set; } // Composite key (StudentID, CourseID)
publicStudent Student { get; set; } // Navigation property
publicCourse Course { get; set; } // Navigation property
}

这些类表示演示关系所需的基本结构。在实际应用程序中,您还需要使用实体框架(或其他 ORM)特定配置(如 Fluent API 或数据注释)配置这些关系,以确保关系在数据库中正确映射。

2. 一对一关系的 LINQ 查询

让我们从最简单的关系开始。考虑两个实体:和 ,每个用户都有一个唯一的配置文件。UserUserProfile

查询语法:

var userWithProfile = from user in context.Users
join profile in context.UserProfiles
on user.ID equals profile.UserID
selectnew { user.Name, profile.ProfilePicture };

方法语法:

var userWithProfile = context.Users
.Join(context.UserProfiles,
user => user.ID,
profile => profile.UserID,
(user, profile) => new { user.Name, profile.ProfilePicture });

在此转换后的查询中:

  • context.Users以及正在连接的两个集合。context.UserProfiles

  • lambda 表达式 和 用于指定连接条件(from 与 from 匹配)。user => user.IDprofile => profile.UserIDIDUsersUserIDUserProfiles

  • 结果选择器创建一个匿名对象,其中包含 from 和 from 。(user, profile) => new { user.Name, profile.ProfilePicture }NameUserProfilePictureUserProfile

  • 此 LINQ 查询检索每个用户及其关联的配置文件图片。

    3. 掌握使用 LINQ 的一对多关系

    一对多关系在数据库中很常见。例如,一个实体可能与多个 .CustomerOrders

    查询语法:

    var customerOrders = from customer in context.Customers
    join order in context.Orders
    on customer.ID equals order.CustomerID
    selectnew { customer.Name, order.OrderID, order.TotalAmount };

    方法语法:

    var customerOrders = context.Customers
    .Join(context.Orders,
    customer => customer.ID,
    order => order.CustomerID,
    (customer, order) => new { customer.Name, order.OrderID, order.TotalAmount });

    在此查询中:

  • context.Customers以及正在连接的两个集合。context.Orders

  • lambda 表达式并指定连接键(from 和 from )。customer => customer.IDorder => order.CustomerIDIDCustomersCustomerIDOrders

  • 最终的 lambda 表达式使用 from 、 和 from 构造一个新的匿名对象。(customer, order) => new { customer.Name, order.OrderID, order.TotalAmount }NameCustomerOrderIDTotalAmountOrder

  • 此查询将为您提供客户列表及其各自的订单。

    4. 驾驭多对多关系

    多对多关系更为复杂。考虑 和 ,其中学生可以注册多门课程,并且每门课程可以有多个学生。StudentsCourses

    在这里,通常使用像 这样的中间表来管理这种关系。StudentCourses

    查询语法:

    var courseEnrollments = from student in context.Students
    join sc in context.StudentCourses on student.ID equals sc.StudentID
    join course in context.Courses on sc.CourseID equals course.ID
    selectnew { student.Name, course.CourseName };

    方法语法:

    var courseEnrollments = context.Students
    .Join(context.StudentCourses,
    student => student.ID,
    sc => sc.StudentID,
    (student, sc) => new { student, sc })
    .Join(context.Courses,
    studentAndSc => studentAndSc.sc.CourseID,
    course => course.ID,
    (studentAndSc, course) => new { studentAndSc.student.Name, course.CourseName });

    在此查询中:

  • 第一个连接。它将每个学生与其课程注册相关联。JoinStudentsStudentCourses

  • 第二个将此中间结果链接到 .它将注册的课程与每个学生相关联。JoinCourses

  • 结果选择器将创建一个匿名对象,其中包含学生的姓名和课程名称。(studentAndSc, course) => new { studentAndSc.student.Name, course.CourseName }

  • 此 LINQ 查询有助于检索每个学生注册的课程。

    5. 高级方案和提示

    1. 关系中的过滤和排序

    假设您要查找特定客户的所有订单并按日期对它们进行排序。以下是使用这两种语法的方法。

    查询语法:

    var sortedOrders = from order in context.Orders
    whereorder.CustomerID == specificCustomerId
    orderby order.OrderDate
    select order;

    方法语法:

    var sortedOrders = context.Orders
    .Where(order => order.CustomerID == specificCustomerId)
    .OrderBy(order => order.OrderDate);

    2. 急切加载与延迟加载示例

    急速加载在单个查询中获取相关数据,而延迟加载则按需获取相关数据。下面是一个急切加载的示例:

    查询语法:

    var customersWithOrders = from customer in context.Customers
    .Include(c => c.Orders)
    select customer;

    方法语法:

    var customersWithOrders = context.Customers
    .Include(c => c.Orders);

    3. 性能注意事项和优化

    了解如何优化 LINQ 查询至关重要,尤其是对于大型数据集。

  • 使用投影:仅选择所需字段,而不是获取整个实体。

  • 避免 N+1 查询:在多对多关系中,请确保不会对每个项目执行其他查询。

  • 批处理操作:对于更新或插入,请考虑使用批处理操作以减少数据库往返。

  • 优化投影示例:

    查询语法:

    var optimizedData = from student in context.Students
    selectnew { student.Name, student.Department };

    方法语法:

    var optimizedData = context.Students
    .Select(student => new { student.Name, student.Department });

    4. 只读方案的 AsNoTracking

    对于只读方案,使用可以通过不跟踪更改来提高性能。AsNoTracking

    查询语法:

    var readOnlyData = context.Students
    .AsNoTracking()
    .Where(s => s.Year == 2);

    方法语法:

    var readOnlyData = from student in context.Students.AsNoTracking()
    wherestudent.Year == 2
    select student;

    结论:使用 LINQ 提升数据库查询技能

    LINQ 是 .NET 库中的一种通用工具,用于处理各种类型的数据库关系。无论是简单的一对一关系还是复杂的多对多方案,LINQ 都能简化和简化流程,使代码更加高效和可维护。

    如果你喜欢我的文章,请给我一个赞!谢谢