如何在C# Npgsql的DbSet实体中映射SQL函数调用作为属性?
EF中映射SQL自定义函数到实体属性的实现方案
你当前的写法不可行,EF(包括EF Core和EF6)并没有SqlFunction<string>这种内置类型来直接把SQL函数映射成实体属性。要实现你的需求,得按以下步骤来:
1. 给SQL函数定义CLR包装方法
在你的DbContext类或者单独的静态类里,用[DbFunction]特性标记一个静态方法,作为SQL函数的CLR映射入口:
public class YourDbContext : DbContext { public DbSet<Table> Tables { get; set; } // 指定SQL函数名和所属架构,比如dbo [DbFunction("some_number", Schema = "dbo")] // 返回类型要和SQL函数一致,你说返回数值的话,把string改成int/decimal等对应类型 public static string SomeNumber(string name) { // 这个方法只是占位,不能直接调用,EF会把它翻译成SQL函数调用 throw new NotSupportedException("仅用于LINQ查询翻译,请勿直接执行"); } }
如果你的SQL函数不需要参数,直接去掉方法里的name参数即可。
2. 在查询中调用该方法获取结果
不需要给实体类加SqlFunction<string>类型的属性,而是通过LINQ查询的投影来获取SQL函数的执行结果:
方式一:投影到匿名类型
直接在查询中调用包装方法,把结果和实体字段一起返回:
var queryResult = db.Tables .Select(t => new { t.Name, // 调用包装方法,传需要的参数(比如当前行的Name) SomeNumber = YourDbContext.SomeNumber(t.Name) }) .ToList();
方式二:投影到实体类(添加只读属性)
如果想让实体类保留这个属性,可以给Table类加一个只读属性,然后在查询时赋值:
class Table { public string Name { get; set; } // 只读属性,仅用于接收查询结果 public string SomeNumber { get; private set; } } // 查询时投影赋值 var tables = db.Tables .Select(t => new Table { Name = t.Name, SomeNumber = YourDbContext.SomeNumber(t.Name) }) .ToList();
3. 注意事项
[DbFunction]的参数必须和SQL函数的名称、架构完全匹配,不然EF无法正确翻译。- 这个CLR包装方法只能在LINQ to Entities查询里用,直接调用会抛出我们定义的异常。
- 如果是EF Core,除了特性标记,也可以用Fluent API配置:
modelBuilder.HasDbFunction(typeof(YourDbContext).GetMethod(nameof(YourDbContext.SomeNumber))!)。
内容的提问来源于stack exchange,提问作者Philskillz
相关产品推荐
相关产品推荐

