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

如何在EF Core中通过SQL函数绑定实体属性并查询数据

问题

我有一个可返回列计算值的SQL函数:

ALTER FUNCTION [dbo].[f_GetCustomValue] 
    (@Id int)
RETURNS VARCHAR(MAX) 
AS
BEGIN
    -- some calculation and joins
END

同时定义了如下实体:

[Table("Country")]
public partial class Country
{
       public int Id { get; set; }
       public string Name { get; set; }
       public string Desc { get; set; }
       public string CustomDesc { get; set; }  // 该属性应取自上述SQL函数的返回值
}

当前查询所有国家的方法如下:

public IQueryable<Country> GetCountries(dbContext context)
{
    return context.Countries; 
}

请问如何修改查询,以获取包含由上述SQL函数计算得到的CustomDesc的国家数据?


解决方案

根据你使用的Entity Framework版本,有以下几种实现方式:

EF Core

方式1:原生SQL查询

直接通过FromSqlRaw或FromSqlInterpolated编写SQL,调用函数填充CustomDesc:

public IQueryable<Country> GetCountries(dbContext context)
{
    return context.Countries.FromSqlRaw(@"
        SELECT 
            Id, 
            Name, 
            [Desc], 
            dbo.f_GetCustomValue(Id) AS CustomDesc
        FROM Country
    ");
}

如果需要添加过滤条件,推荐使用FromSqlInterpolated避免SQL注入:

public IQueryable<Country> GetCountries(dbContext context, int? filterId = null)
{
    var baseQuery = @"
        SELECT 
            Id, 
            Name, 
            [Desc], 
            dbo.f_GetCustomValue(Id) AS CustomDesc
        FROM Country";

    return filterId.HasValue 
        ? context.Countries.FromSqlInterpolated($"{baseQuery} WHERE Id = {filterId}")
        : context.Countries.FromSqlInterpolated(baseQuery);
}

方式2:注册函数后用LINQ调用

先在DbContext中注册SQL函数,并定义对应的CLR方法:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 注册SQL函数
    modelBuilder.HasDbFunction(() => DbContextExtensions.f_GetCustomValue(default(int)))
                .HasName("f_GetCustomValue")
                .HasSchema("dbo");
}

// 定义静态CLR方法(可放在DbContext或单独的扩展类中)
public static class DbContextExtensions
{
    [DbFunction("f_GetCustomValue", Schema = "dbo")]
    public static string f_GetCustomValue(int id)
    {
        // 该方法仅用于EF Core生成SQL,不会在内存中执行
        throw new NotImplementedException();
    }
}

之后就可以在LINQ查询中直接调用函数:

public IQueryable<Country> GetCountries(dbContext context)
{
    return context.Countries
                  .Select(c => new Country
                  {
                      Id = c.Id,
                      Name = c.Name,
                      Desc = c.Desc,
                      CustomDesc = DbContextExtensions.f_GetCustomValue(c.Id)
                  });
}

EF6

方式1:原生SQL查询

使用SqlQuery执行原生SQL语句:

public IQueryable<Country> GetCountries(dbContext context)
{
    return context.Countries.SqlQuery(@"
        SELECT 
            Id, 
            Name, 
            [Desc], 
            dbo.f_GetCustomValue(Id) AS CustomDesc
        FROM Country
    ").AsQueryable();
}

方式2:映射函数后用LINQ调用

在DbContext中定义映射到SQL函数的方法:

[DbFunction("YourModelNamespace", "f_GetCustomValue")]
public string f_GetCustomValue(int id)
{
    // 直接调用无效,仅用于LINQ查询生成SQL
    throw new NotSupportedException();
}

如果是Code First,需要确保EDMX或Fluent API中完成了函数映射,之后即可通过LINQ查询:

public IQueryable<Country> GetCountries(dbContext context)
{
    return context.Countries
                  .Select(c => new Country
                  {
                      Id = c.Id,
                      Name = c.Name,
                      Desc = c.Desc,
                      CustomDesc = context.f_GetCustomValue(c.Id)
                  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:26