如何在Entity Framework Core 7中为Cosmos DB添加ToString函数支持以实现数字包含查询?
如何在Entity Framework Core 7中为Cosmos DB添加ToString函数支持以实现数字包含查询?
你遇到的这个问题确实挺常见的——EF Core 7对Cosmos DB的内置函数支持并没有覆盖到ToString(),不过咱们可以通过自定义数据库函数映射来解决这个问题,下面一步步来实现:
步骤1:定义自定义函数的静态类
首先创建一个静态类,用来声明我们要使用的ToString方法,并用[DbFunction]特性标记,告诉EF Core这是一个需要映射到数据库的函数:
public static class CosmosDbFunctions { // 标记为数据库函数,第二个参数留空因为Cosmos不需要schema [DbFunction("ToString", "")] public static string ToString(int value) { // 这个方法只用于EF的查询翻译,实际不会在内存执行,所以直接抛异常即可 throw new NotImplementedException("此方法仅用于EF Core查询翻译,请勿直接调用"); } // 如果你的ChargingSessionId是long类型,添加对应的重载 [DbFunction("ToString", "")] public static string ToString(long value) { throw new NotImplementedException("此方法仅用于EF Core查询翻译,请勿直接调用"); } }
步骤2:在DbContext中注册函数映射
接下来在你的DbContext的OnModelCreating方法里,把这个自定义函数注册到EF Core,并指定它要翻译成Cosmos DB的内置ToString函数:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 注册int类型的ToString函数 var intToStringMethod = typeof(CosmosDbFunctions).GetMethod(nameof(CosmosDbFunctions.ToString), new[] { typeof(int) })!; modelBuilder.HasDbFunction(intToStringMethod) .HasTranslation(args => new SqlFunctionExpression( functionName: "ToString", arguments: args, nullable: true, argumentsPropagateNullability: new[] { true }, type: typeof(string), typeMapping: null)); // 如果有long类型的重载,同样注册 var longToStringMethod = typeof(CosmosDbFunctions).GetMethod(nameof(CosmosDbFunctions.ToString), new[] { typeof(long) })!; modelBuilder.HasDbFunction(longToStringMethod) .HasTranslation(args => new SqlFunctionExpression( functionName: "ToString", arguments: args, nullable: true, argumentsPropagateNullability: new[] { true }, type: typeof(string), typeMapping: null)); }
步骤3:在LINQ查询中使用自定义函数
现在你就可以在查询里用这个自定义的ToString方法代替.NET原生的ToString()了:
query.Where(x => CosmosDbFunctions.ToString(x.ChargingSessionId).Contains("7"));
这样EF Core就会准确翻译成你期望的Cosmos SQL:
SELECT * FROM c WHERE CONTAINS(ToString(c.ChargingSessionId), "7")
可选的替代方案:存储字符串副本
如果觉得自定义函数有点麻烦,还有一个更简单的 workaround:在你的实体类里额外添加一个字符串类型的属性,比如ChargingSessionIdStr,在保存实体的时候同步把ChargingSessionId转成字符串赋值给它。之后查询直接用这个字符串属性的Contains:
// 实体类 public class YourEntity { public int ChargingSessionId { get; set; } public string ChargingSessionIdStr { get; set; } = string.Empty; // 可以在构造函数或者保存前的逻辑里同步值 public YourEntity() { ChargingSessionIdStr = ChargingSessionId.ToString(); } } // 查询时 query.Where(x => x.ChargingSessionIdStr.Contains("7"));
这个方案的优点是实现简单,缺点是会增加存储量,且需要维护两个属性的一致性,适合查询频率很高的场景。
备注:内容来源于stack exchange,提问作者Akino
相关产品推荐
相关产品推荐

