Linq 和 lambda 联接查询

如果有数据库相关的知识,应该都很熟联接查询。在 C# 里了提供了强大的 Linq 和 lambda 联接查询。今天我们就来看下它们的用法。

执行联接操作方法

Linq 中有两种方法可用于执行联接操作。

  1. Join 基于公共属性来联接两个或多个数据源,并返回单个结果集。

  2. GroupJoin 基于公共属性(或公共键)联接两个或多个数据源,并返回一组序列的结果集。

lambda 的用法只有一个 join 就可以执行联接操作。

准备

先建三个类,用户类(User),角色类(Role),用户角色(UserRole),具体如下 :  

public class User {
    public int Id { get; set; }
    public string UserName { get; set; }
    
    public virtual UserRole UserRole { get; set; }
}

public class Role {
    public int Id { get; set; }
    public string Name { get; set; }
    
    public virtual UserRole UserRole { get; set; }
}

public class UserRole {
    public int UserId { get; set; }
    public int RoleId { get; set; }
    
    public virtual User User { get; set; }

    public virtual Role Role { get; set; }
}

 创建一个继承 DbContext 的类,类名叫 YldDbContext 。该类具体如下:

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

    }

    public DbSet<User> Users { get; set; }

    public DbSet<Role> Roles { get; set; }

    public DbSet<UserRole> UserRoles { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        var roleBuilder = modelBuilder.Entity<Role>();
        roleBuilder.ToTable("roles");
        roleBuilder.HasKey(a => a.Id);
        roleBuilder.Property(a => a.Id).HasColumnName("RoleId").ValueGeneratedOnAdd();
        roleBuilder.HasOne(a => a.UserRole).WithOne(a => a.Role).HasForeignKey<UserRole>(a => a.RoleId);
        
        var userBuilder = modelBuilder.Entity<User>();
        userBuilder.ToTable("users");
        userBuilder.HasKey(a => a.Id);
        userBuilder.Property(a => a.Id).HasColumnName("UserId").ValueGeneratedOnAdd();
        userBuilder.HasOne(a => a.UserRole).WithOne(a => a.User).HasForeignKey<UserRole>(a => a.UserId);
        
        base.OnModelCreating(modelBuilder);

    }
}

 示例 1

查询用户与角色对应的数据,Linq 的用法如下:

private readonly YldContext _context;  //通过注入实例化

var results = await _context.Users.Join(_context.UserRoles, u => u.Id, ur => ur.UserId, (u, ur) => new { UserId = u.Id, u.UserName, RoleId = ur.RoleId })
                .Join(_context.Roles, t => t.RoleId, r => r.Id, (t, r) => new { t.UserId, t.UserName, t.RoleId, RoleName = r.Name })
                .ToListAsync();

返回的结果如下:

[
    {
        "userId": 48,
        "userName": "admin",
        "roleId": 1,
        "roleName": "管理员"
    },
    {
        "userId": 59,
        "userName": "sa",
        "roleId": 136,
        "roleName": "administrator"
    }
]

 Join 方法参数说明:

Join(右边集合,左边关联属性(左表主键),右边关联属性(右表主键),返回集合对象(临时表))

使用 Join 生成对应的 SQL 如下:

SELECT `u`.`UserId`, `u`.`UserName`, `r`.`RoleId`, `r`.`Name` AS RoleName
FROM `users` AS `u`
INNER JOIN `userroles` AS `ur` ON `u`.`UserId` = `ur`.`UserId`
INNER JOIN `roles` AS `r` ON `ur`.`RoleId` = `r`.`RoleId`

 返回的结果、生成的 SQL 与 Linq 一样。

lambda 关联主外键时是用 equals。但过滤条件仍是 Linq 表达式。

示例 2

假设我要查询一个用户配置和未配置的角色列表,如下图:

 Linq 提供了一个 GroupJoin 的方法。具体用法如下:

private readonly YldContext _context;  //通过注入实例化

var results = await _context.Roles.GroupJoin(_context.UserRoles, r => new { RoleId = r.Id, UserId = 48 }, ur => new { ur.RoleId, ur.UserId} , (r, ur) => new { Role = r, UserRole = ur })
    .SelectMany(t => t.UserRole.DefaultIfEmpty(), (r, ur) => new { RoleId = r.Role.Id, RoleName = r.Role.Name, IsSet = ur==null);

返回结果如下:

[
    {
        "id": 1,
        "name": "管理员",
        "isCheckd": true
    },
    {
        "id": 117,
        "name": "aaa",
        "isCheckd": false
    },
    {
        "id": 136,
        "name": "administrator",
        "isCheckd": false
    }
]

GroupJoin 方法参数说明:

GroupJoin(右边集合,左边关联属性(左表主键),右边关联属性(右表主键),返回集合对象(临时表))

在 GroupJoin 方法里使用匿名对象创建一个组合属性来联接两个资源,这里有一个注意的点:左右两边的匿名对象属性名及类型要一致。

使用 GroupJoin 方法生成对应的 SQL 语句如下:

SELECT `r`.`RoleId`, `r`.`Name` AS `RoleName`, `u`.`Id` IS NULL AS `IsSet`
FROM `roles` AS `r`
LEFT JOIN `userroles` AS `u` ON (`r`.`RoleId` = `u`.`RoleId`) AND (48 = `u`.`UserId`)

 再来看下 lambda 的写法:

from r in Roles
join ur in Userroles on new { RoleId = r.RoleId, UserId = 48 } equals new { ur.RoleId, ur.UserId } into temp
from t in temp.DefaultIfEmpty()
select new { r.RoleId, RoleName = r.Name, IsSet = t == null }

 返回的结果、生成的 SQL 与 Linq 一样。

今天的 Linq 和 lambda 联接查询的基本内容就到这。

最后,祝大家学习愉快!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值