克服 MongoDB C# 驱动程序的局限性

mongodb 驱动程序有其局限性,有时您需要手动或使用查询编辑器/编写器编写高级查询。为了能够运行这些查询并从 C# 代码中注入值,您需要编写BsonDocuments或执行字符串连接,这会导致丑陋、不可读、充满魔法字符串的令人憎恶的结果。

为了解决这个问题,并将您的 C# 实体模式与原始查询结合起来,库MongoDB.Entities提供了一个基于标签替换的模板系统。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

以以下查找查询为例:

db.Book.find(
  {
    Title : 'book_name',
    Price : book_price
  }
)

要将此文本查询与您的 C# 模型耦合并传入标题和价格的值,只需将您想要替换的部分括起来<>然后将它们转换为替换标签/标记,如下所示:

db.Book.find(
  {
    <Title> : '<book_name>',
    <Price> : <book_price>
  }
)

模板系统基于一个名为的特殊类Template。您只需实例化一个“模板”对象,将标记的文本查询提供给构造函数。然后,您在模板对象上链接方法调用来替换您在查询上标记的每个标签,如下所示:

var query = new Template<Book>(@"
{
  <Title> : '<book_name>',
  <Price> : <book_price>
}")
.Path(b => b.Title)    
.Path(b => b.Price)
.Tag("book_name","The Power Of Now")
.Tag("book_price","10.95");

var result = await DB.Find<Book>()
                     .Match(query)
                     .ExecuteAsync();

发送给 mongodb 的结果查询如下:

db.Book.find(
  {
    Title : 'The Power Of Now',
    Price : 10.95
  }
)

该方法只是用提供的值替换文本查询中匹配的标签。使用该方法时.Tag()不必使用<和字符。事实上,避免使用它,因为如果使用它们,标签将不匹配。>.Tag()

.Path()方法是该类提供的众多方法之一,您可以使用它通过提供 lambda/成员表达式来获取属性的完整“点状”路径。请参阅此处的Prop“Prop”类的文档,了解其他可用方法。

请注意,大多数这些“Prop”方法只需要一个参数。您向它们提供的任何成员表达式都会转换为这样的属性/字段路径:

表达式:x => x.Authors[0].Books[0].Title

结果路径:Authors.Books.Title

如果您的文本查询有标签,<Authors.Books.Title>它将被“Prop”类方法的结果路径替换。

当发生以下3种情况时,模板系统将会抛出异常。

  1. 输入的查询/文本没有使用<>字符标记的标签。
  2. 输入查询包含您忘记指定替换的标签。
  3. 您指定的替换项在查询中没有匹配的标签。

这种运行时错误比由于查询没有产生任何结果或产生错误结果而导致代码默默失败要好。

一些例子:

聚合管道:

var pipeline = new Template<Book>(@"
[
    {
      $match: { <Title>: '<book_name>' }
    },
    {
      $sort: { <Price>: 1 }
    },
    {
      $group: {
        _id: '$<AuthorId>',
        product: { $first: '$$ROOT' }
      }
    },
    {
      $replaceWith: '$product'
    }
]")
.Path(b => b.Title)
.Path(b => b.Price)
.Path(b => b.AuthorId)
.Tag("book_name", "MongoDB Templates");

var book = await DB.PipelineSingleAsync(pipeline);

使用匹配表达式查找:

var query = new Template<Author>(@"
{
  $and: [
    { $gt: [ '$<Age>', <author_age> ] },
    { $eq: [ '$<Surname>', '<author_surname>' ] }
  ]
}")
.Path(a => a.Age)
.Path(a => a.Surname)
.Tag("author_age", "54")
.Tag("author_surname", "Tolle");

var authors = await DB.Find<Author>()
                      .MatchExpression(query)
                      .ExecuteAsync();

使用聚合管道阶段进行更新:

var pipeline = new Template<Author>(@"
[
  { $set: { <FullName>: { $concat: ['$<Name>',' ','$<Surname>'] } } },
  { $unset: '<Age>'}
]")             
.Path(a => a.FullName)
.Path(a => a.Name)
.Path(a => a.Surname)
.Path(a => a.Age);

await DB.Update<Author>()
        .Match(a => a.ID == "xxxxx")
        .WithPipeline(pipeline)
        .ExecutePipelineAsync();

使用数组过滤器进行更新:

var filters = new Template<Author>(@"
[
  { '<a.Age>': { $gte: <age> } },
  { '<b.Name>': 'Echkart Tolle' }
]")
.Elements(0, author => author.Age)
.Elements(1, author => author.Name);
.Tag("age", "55")        

var update = new Template<Book>(@"
{ $set: { 
    '<Authors.$[a].Age>': <age>,
    '<Authors.$[b].Name>': '<name>'
  } 
}")
.PosFiltered(book => book.Authors[0].Age)
.PosFiltered(book => book.Authors[1].Name)
.Tag("age", "55")
.Tag("name", "Updated Name");

await DB.Update<Book>()
        .Match(book => book.ID == "xxxxxxxx")
        .WithArrayFilters(filters)
        .Modify(update)
        .ExecuteAsync();

后续步骤...

希望上述文本查询模板系统能够激发您的兴趣,让您更深入地学习如何使用 C# 来使用 MongoDB。该软件包MongoDB.Entities让您能够非常轻松地与 MongoDB 服务器通信。其 API 的各个方面均已在官方网站上记录。您也可以在 GitHub 上查看源代码:https://github.com/dj-nitehawk/MongoDB.Entities

参考文章:Overcoming The Limitations Of MongoDB C# Driver - DEV Community

Welcome | MongoDB.Entities

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hefeng_aspnet

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值