You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Entity Framework单表绑定服务下多表关联及原生SQL执行方案

解决方案

一、基于EF的多表关联查询

要实现多表关联,首先确保你的实体类和DbContext已经正确配置了表间的关联关系(外键+导航属性),之后就可以通过EF的LINQ语法完成关联查询。

步骤1:确认实体关联配置

假设你需要关联User表和Order表,先在实体类中定义导航属性:

// UserItem 实体(对应User表)
public class UserItem
{
    public string Telephone { get; set; }
    // 导航属性:一个用户对应多个订单
    public ICollection<OrderItem> Orders { get; set; }
}

// OrderItem 实体(对应Order表)
public class OrderItem
{
    public int Id { get; set; }
    public string UserTelephone { get; set; } // 外键,关联User表的Telephone
    // 导航属性:一个订单属于一个用户
    public UserItem User { get; set; }
}

同时在你的DbContext中注册对应的DbSet:

public DbSet<UserItem> Users { get; set; }
public DbSet<OrderItem> Orders { get; set; }

步骤2:编写关联查询代码

可以用两种方式实现关联查询:

方式1:Include加载关联数据(适合一对一/一对多场景)

通过Include直接加载实体的导航属性,简化关联逻辑:

public async Task<IEnumerable<UserItem>?> GetUserWithOrders(string telephone)
{
    await InitializeAsync();
    try
    {
        return await _context.Users
                           .Include(u => u.Orders) // 加载关联的订单数据
                           .Where(u => u.Telephone == telephone)
                           .ToListAsync();
    }
    catch (Exception e)
    {
        // 建议添加日志记录,方便排查问题
        return null;
    }
}

方式2:手动Join查询(适合复杂关联场景)

如果需要自定义返回字段或多表交叉关联,用Join手动关联:

public async Task<IEnumerable<object>?> GetUserOrderDetails(string telephone)
{
    await InitializeAsync();
    try
    {
        return await _context.Users
                           .Join(_context.Orders,
                                 user => user.Telephone,
                                 order => order.UserTelephone,
                                 (user, order) => new 
                                 {
                                     UserName = user.Name,
                                     OrderId = order.Id,
                                     OrderDate = order.CreateTime
                                 })
                           .Where(x => x.UserTelephone == telephone)
                           .ToListAsync();
    }
    catch (Exception e)
    {
        return null;
    }
}

二、执行原生SQL语句

如果需要直接执行FROM TABLE XYZ开头的原生SQL,EF Core提供了FromSqlRaw方法,支持异步执行且可通过参数化避免SQL注入:

示例1:单表原生SQL查询

public async Task<IEnumerable<UserItem>?> GetUserByTelephoneRawSql(string telephone)
{
    await InitializeAsync();
    try
    {
        // 参数化查询,杜绝SQL注入风险
        var sql = "SELECT * FROM Users WHERE Telephone = @telephone";
        return await _context.Users
                           .FromSqlRaw(sql, new SqlParameter("@telephone", telephone))
                           .ToListAsync();
    }
    catch (Exception e)
    {
        return null;
    }
}

示例2:多表关联的原生SQL查询

如果需要关联多表并返回自定义结果,先定义DTO接收数据,再执行SQL:

// 定义DTO接收查询结果
public class UserOrderDto
{
    public string UserTelephone { get; set; }
    public string UserName { get; set; }
    public int OrderId { get; set; }
}

public async Task<IEnumerable<UserOrderDto>?> GetUserOrderRawSql(string telephone)
{
    await InitializeAsync();
    try
    {
        var sql = @"SELECT u.Telephone AS UserTelephone, u.Name AS UserName, o.Id AS OrderId
                    FROM Users u
                    JOIN Orders o ON u.Telephone = o.UserTelephone
                    WHERE u.Telephone = @telephone";
        return await _context.Set<UserOrderDto>()
                           .FromSqlRaw(sql, new SqlParameter("@telephone", telephone))
                           .ToListAsync();
    }
    catch (Exception e)
    {
        return null;
    }
}

注意事项

  • 必须使用参数化查询,避免SQL注入;
  • 如果你的Azure服务是Cosmos DB等NoSQL数据库,关联逻辑需调整,但从描述看是关系型数据库,上述方案适用;
  • catch块建议添加日志记录,不要仅返回null,便于后续排查问题。

内容的提问来源于stack exchange,提问作者inno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:35:18