使用 MongoDB.Driver 将 lambda 表达式转换为 json 对象
Convert lambda expressions to json objects using MongoDB.Driver
我需要将查询作为字符串而不是 lambda 表达式来执行,因为我很难使用模拟框架来为我的项目创建单元测试。
换句话说,我想修改我的 IDatabase
接口来自:
Interface IDatabase
{
IEnumerable<User> Find(Expression<Func<User, bool>> filter);
}
收件人:
Interface IDatabase
{
IEnumerable<User> Find(string query);
}
我已经有很多用表达式编写的查询。因此,我创建了这段代码来将表达式转换为 JSON 对象:
using MongoDB.Driver;
using System.Linq.Expressions;
class Program
{
// Example of a collection I store on my DB
class User
{
public string _id { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
}
// Main method
public static void Main()
{
var json = ExpressionToJson<User>(x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow);
// outputs:
// { "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:21:27.975Z") } }
Console.WriteLine(json);
}
/// <summary>
/// Method that will convert an expression to a string
/// </summary>
public static string ExpressionToJson<T>(Expression<Func<T, bool>> filter)
{
MongoClient MongoClient = new MongoClient();
var db1 = MongoClient.GetDatabase("DoesNotMatter");
var collection = db1.GetCollection<T>("DoesNotMatter");
var query = collection.Find(filter);
var json = query.ToString();
if (string.IsNullOrEmpty(json))
return "{}";
// json should look something like this
// find({ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:11:47.772Z") } })
// remove the find( at the beginning and last parenthesis
if (json.StartsWith("find("))
return json.Substring(5, json.Length - 6);
throw new NotImplementedException("Did serializer changed?");
}
}
如您所见,这段代码可以转换表达式
x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow
到JSON
{ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:24:38.628Z") } }
如何简化 ExpressionToJson
方法?如果我可以避免创建一个 MongoClient
的实例然后一个数据库的实例然后一个 IMongoCollection<TDocument>
的实例来序列化我需要的表达式,那将会很酷。
或许,你可以写一个IMongoCollection
扩展方法,采用IFindFluent<T, T>.Filter.Render
(类似于)生成JSON中的过滤查询。
public static class IMongoCollectionExtensions
{
public static string ExpressionToJson<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> filter)
{
var query = collection.Find(filter);
return query.Filter.Render(
collection.DocumentSerializer,
collection.Settings.SerializerRegistry
).ToJson();
}
}
var jsonQuery = collection.ExpressionToJson<User>(x => x.Name.Contains("Tono")
&& x.DateCreated < DateTime.UtcNow);
Output
我需要将查询作为字符串而不是 lambda 表达式来执行,因为我很难使用模拟框架来为我的项目创建单元测试。
换句话说,我想修改我的 IDatabase
接口来自:
Interface IDatabase
{
IEnumerable<User> Find(Expression<Func<User, bool>> filter);
}
收件人:
Interface IDatabase
{
IEnumerable<User> Find(string query);
}
我已经有很多用表达式编写的查询。因此,我创建了这段代码来将表达式转换为 JSON 对象:
using MongoDB.Driver;
using System.Linq.Expressions;
class Program
{
// Example of a collection I store on my DB
class User
{
public string _id { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
}
// Main method
public static void Main()
{
var json = ExpressionToJson<User>(x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow);
// outputs:
// { "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:21:27.975Z") } }
Console.WriteLine(json);
}
/// <summary>
/// Method that will convert an expression to a string
/// </summary>
public static string ExpressionToJson<T>(Expression<Func<T, bool>> filter)
{
MongoClient MongoClient = new MongoClient();
var db1 = MongoClient.GetDatabase("DoesNotMatter");
var collection = db1.GetCollection<T>("DoesNotMatter");
var query = collection.Find(filter);
var json = query.ToString();
if (string.IsNullOrEmpty(json))
return "{}";
// json should look something like this
// find({ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:11:47.772Z") } })
// remove the find( at the beginning and last parenthesis
if (json.StartsWith("find("))
return json.Substring(5, json.Length - 6);
throw new NotImplementedException("Did serializer changed?");
}
}
如您所见,这段代码可以转换表达式
x => x.Name.Contains("Tono") && x.DateCreated < DateTime.UtcNow
到JSON
{ "Name" : /Tono/s, "DateCreated" : { "$lt" : ISODate("2022-01-21T01:24:38.628Z") } }
如何简化 ExpressionToJson
方法?如果我可以避免创建一个 MongoClient
的实例然后一个数据库的实例然后一个 IMongoCollection<TDocument>
的实例来序列化我需要的表达式,那将会很酷。
或许,你可以写一个IMongoCollection
扩展方法,采用IFindFluent<T, T>.Filter.Render
(类似于
public static class IMongoCollectionExtensions
{
public static string ExpressionToJson<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> filter)
{
var query = collection.Find(filter);
return query.Filter.Render(
collection.DocumentSerializer,
collection.Settings.SerializerRegistry
).ToJson();
}
}
var jsonQuery = collection.ExpressionToJson<User>(x => x.Name.Contains("Tono")
&& x.DateCreated < DateTime.UtcNow);
Output