如何将C#方法映射到SQL函数并调用TestBool函数
如何让EF Core调用SQL函数TestBool并获取返回值
问题现状
你已在SQL Server中创建TestBool函数,也在EF Core的DbContext里添加了标记[DbFunction]的静态方法,但直接调用会抛出异常,函数无法正常工作。
现有代码的问题点
- 类型不匹配:SQL函数返回
BIT类型,对应C#的bool,但你定义的TestBool方法返回int,类型不兼容。 - 未注册函数映射:EF Core不知道这个C#方法对应数据库里的哪个函数,需要在
OnModelCreating中显式关联。 - 调用方式错误:直接调用静态方法会触发
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
相关产品推荐
相关产品推荐

