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

如何将C#方法映射到SQL函数并调用TestBool函数

如何让EF Core调用SQL函数TestBool并获取返回值

问题现状

你已在SQL Server中创建TestBool函数,也在EF Core的DbContext里添加了标记[DbFunction]的静态方法,但直接调用会抛出异常,函数无法正常工作。

现有代码的问题点

  1. 类型不匹配:SQL函数返回BIT类型,对应C#的bool,但你定义的TestBool方法返回int,类型不兼容。
  2. 未注册函数映射:EF Core不知道这个C#方法对应数据库里的哪个函数,需要在OnModelCreating中显式关联。
  3. 调用方式错误:直接调用静态方法会触发NotImplementedException,必须通过EF的LINQ查询让框架把方法翻译成SQL执行,而非本地执行。

修正步骤

步骤1:修正DbFunction的方法签名

修改JanaruContext里的TestBool方法,让返回类型和参数类型与SQL函数完全匹配:

[DbFunction]
public static bool TestBool(bool test)
{
    throw new NotImplementedException("该方法仅用于EF Core生成SQL,不能直接调用");
}

步骤2:在OnModelCreating中注册函数映射

在OnModelCreating方法内添加函数注册代码,明确告诉EF Core这个C#方法对应数据库的dbo.TestBool函数:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 原有实体配置代码...

    // 注册TestBool函数
    modelBuilder.HasDbFunction(typeof(JanaruContext).GetMethod(nameof(JanaruContext.TestBool))!)
        .HasName("TestBool")
        .HasSchema("dbo");

    OnModelCreatingPartial(modelBuilder);
}

步骤3:正确调用函数(通过LINQ查询)

不能直接调用静态方法,要通过EF的查询机制触发SQL执行。比如修改控制器的调用逻辑:

[HttpGet(Name = "GetWeatherForecast")]
public async Task<bool> Get()
{
    // 方式1:直接调用函数获取结果
    var result = await _db.Set<bool>()
        .FromSqlRaw("SELECT dbo.TestBool({0})", true)
        .FirstOrDefaultAsync();

    // 方式2:结合实体查询使用函数
    // var entityWithResult = await _db.Ttest1s
    //     .Select(t => new { t.Id, BoolResult = JanaruContext.TestBool(true) })
    //     .FirstOrDefaultAsync();

    return result;
}

完整修正后的代码示例

修正后的JanaruContext

using System;
using System.Collections.Generic;
using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace CreateFunctionApp.Entities
{
    public partial class JanaruContext : DbContext
    {
        public JanaruContext()
        {
        }

        public JanaruContext(DbContextOptions<JanaruContext> options)
            : base(options)
        {
        }

        public virtual DbSet<Ttest1> Ttest1s { get; set; } = null!;
        public virtual DbSet<Ttest2> Ttest2s { get; set; } = null!;
        public virtual DbSet<Ttest3> Ttest3s { get; set; } = null!;

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // 此处需配置数据库连接字符串,示例:
            // optionsBuilder.UseSqlServer("Server=你的服务器;Database=你的库名;Trusted_Connection=True;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Ttest1>(entity =>
            {
                entity.ToTable("TTest1");

                entity.Property(e => e.Id).HasColumnName("id");

                entity.Property(e => e.Date)
                    .HasColumnType("datetime")
                    .HasColumnName("date");

                entity.Property(e => e.Isbn)
                    .HasMaxLength(50)
                    .IsUnicode(false)
                    .HasColumnName("isbn");

                entity.Property(e => e.Score).HasColumnName("score");
            });

            modelBuilder.Entity<Ttest2>(entity =>
            {
                entity.ToTable("TTest2");

                entity.Property(e => e.Id).HasColumnName("id");

                entity.Property(e => e.Date)
                    .HasColumnType("datetime")
                    .HasColumnName("date");

                entity.Property(e => e.Isbn)
                    .HasMaxLength(50)
                    .IsUnicode(false)
                    .HasColumnName("isbn");

                entity.Property(e => e.Score).HasColumnName("score");
            });

            modelBuilder.Entity<Ttest3>(entity =>
            {
                entity.ToTable("TTest3");

                entity.Property(e => e.Ttest3Id).HasColumnName("TTest3Id");

                entity.Property(e => e.Date)
                    .HasColumnType("datetime")
                    .HasColumnName("date");

                entity.Property(e => e.Isbn)
                    .HasMaxLength(50)
                    .IsUnicode(false)
                    .HasColumnName("isbn");

                entity.Property(e => e.Score).HasColumnName("score");
            });

            // 注册TestBool数据库函数
            modelBuilder.HasDbFunction(typeof(JanaruContext).GetMethod(nameof(JanaruContext.TestBool))!)
                .HasName("TestBool")
                .HasSchema("dbo");

            OnModelCreatingPartial(modelBuilder);
        }

        [DbFunction]
        public static bool TestBool(bool test)
        {
            throw new NotImplementedException("该方法仅用于EF Core生成SQL语句,请勿直接调用");
        }

        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
}

修正后的控制器代码

using CreateFunctionApp.Entities;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace CreateFunctionApp.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly ILogger<WeatherForecastController> _logger;
        private readonly JanaruContext _db;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, JanaruContext db)
        {
            _logger = logger;
            _db = db;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public async Task<IActionResult> Get()
        {
            // 调用数据库函数并获取结果
            bool functionResult = await _db.Set<bool>()
                .FromSqlRaw("SELECT dbo.TestBool({0})", true)
                .FirstOrDefaultAsync();

            return Ok(new { Result = functionResult });
        }
    }
}

注意事项

  • 必须确保DbContext的OnConfiguring方法里配置了正确的数据库连接字符串,否则无法连接数据库执行函数。
  • 标记[DbFunction]的方法本身不会执行逻辑,仅作为EF Core生成SQL的标记,直接调用必然抛出异常,这是正常设计。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 06:12:03