65.9K
CodeProject 正在变化。 阅读更多。
Home

使用官方 C# 驱动程序与 MongoDB 结合使用

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (27投票s)

2011 年 10 月 24 日

CPOL

6分钟阅读

viewsIcon

161476

downloadIcon

3884

介绍如何使用官方 C# 驱动程序在 ASP.NET MVC 项目中使用 MongoDB。

引言

MongoDB 是 NoSQL 世界中一个引人注目的应用,它通过驱动程序、全面的文档和相当大的社区提供了大量支持,可以用于构建使用 NoSQL 技术的应用程序,而不是直接转向 MS SQL Server 和 Oracle 等关系数据库管理系统。

在本文中,我想介绍如何使用官方 C# 驱动程序来使用 MongoDB。这个驱动程序有一些替代方案,其中一些甚至被认为更好,提供了额外的功能,如 LINQ 支持,但我更喜欢在我的项目中使用这个驱动程序,因为它得到了官方支持。

代码示例取自演示项目。我建议您仔细研究演示项目,因为这样您会理解得更好,并且可以选择尝试 MongoDB。

关于 MongoDB 数据结构的一些说明

在 MongoDB 中,数据结构和层次结构如下:

Databases
   Collections
      Documents
         Fields

字段是键值对。键是名称(字符串)。值是基本类型,如字符串、整数、浮点数、时间戳、二进制等,或者是一个文档,或者是一个值数组。

简而言之,集合是由类 JSON 文档组成的。这是与传统关系数据库管理系统最大的区别,因此请尝试将您的数据视为真实对象,而不是纯数据。此外,您将在官方驱动程序中看到以 Bson 开头的类。

bsonspec.org 对 BSON 的定义是 JSON 类文档的二进制编码序列化。BSON 被设计成轻量级、可遍历且高效。BSON 就像 JSON 一样,支持在其他对象和数组中嵌入对象和数组。

准备工作

首先,从以下地址下载合适的 MongoDB 包并执行 mongod.exe 来启动您的 MongoDB 服务器。

如果您在启动服务器时遇到与路径相关的问题,请创建一个文件夹来存储数据库文件,并使用 dbpath 参数启动 mongod.exe,将文件夹路径作为以下行所示给出:

mongod.exe --dbpath "C:\data"

为了使用此驱动程序,请从以下链接下载所需的程序集文件:

在这里,您可以获取源代码并下载安装包。当您下载了合适的包并安装它后,您就可以在 Program Files Folder\MongoDB\CSharpDriver 1.2 路径下找到以下两个程序集文件。顺便说一下,我在本文中使用了 CSharpDriver-1.2.0.4274.msi

  • MongoDB.Bson.dll
  • MongoDB.Driver.dll

您需要将这两个文件作为引用添加到您的项目中。MongoDB.Bson.dll 用于 BSON 序列化,另一个用于数据库通信。现在,您已准备好使用 MongoDB 开发您的项目。

服务器启动

首先,您应该确保 MongoDB 正在运行,并且您指向服务器正在运行的端口是正确的。下面您可以看到从命令行启动 MongoDB 服务器时的输出。

MongoDB server running

在屏幕上,端口用红色框标出。然后,通过运行 mongo.exe 启动 MongoDB 控制台,并运行以下行来创建您的数据库:

use MessageDB

现在您已完成 MongoDB 服务器的设置。

Application

我们将使用这两个命名空间来与我们的 MongoDB 服务器和数据进行通信和处理,所以请添加以下行:

using MongoDB.Driver;
using MongoDB.Bson;

// Create server settings to pass connection string, timeout, etc.
MongoServerSettings settings = new MongoServerSettings();
settings.Server = new MongoServerAddress("localhost", 27017);
// Create server object to communicate with our server
MongoServer server = new MongoServer(settings);
// Get our database instance to reach collections and data
var database = server.GetDatabase("MessageDB");

在这些行中,我们创建一个服务器对象,并传入所需的设置,如凭据、连接字符串、端口等。在此示例中,我们使用 localhost 作为数据库服务器,27017 作为服务器端口。然后,我们访问之前创建的数据库 MessageDB。有了数据库对象,我们就可以进行 CRUD 操作了。

读取

var users = database.GetCollection("users").
                            FindAll().
                            SetSortOrder(SortBy.Descending("createdate"));

官方驱动程序提供了多种访问和处理数据的方式。在上面的行中,我们首先使用 createdate 值按顺序访问 users 集合。也可以通过索引 [] 访问集合或其他兼容集合,例如 datasase["users"]

foreach (var user in users)
{
    var userName = user["firstname"].AsString;
    ...
}

在获取结果(无论是 BSON 格式还是强类型对象格式)后,我们可以对其进行迭代。

可以使用 Query 编写复杂的查询。

var query = Query.And(
                Query.Matches("firstname", BsonRegularExpression.Create("^e")),
                Query.GT("createdate", BsonValue.Create(DateTime.Now.AddDays(-7).Date)));

// Get all users whose firstname starts with 'e' and who are
// created within last 7 days in sorted format by createdate
var users = database.
                GetCollection("users").
                Find(query).
                SetSortOrder(SortBy.Descending("createdate"));

您可以通过如下方式获取从对象转换为 MongoDB 表示的查询:

MongoDB query

编辑

当我们获取数据时,我们可以直接编辑值,并通过调用相关集合的 Save 方法来保存更新的文档。在以下行中,我们通过提供 ID 值来获取一个唯一文档。

// Update user by id
var user = users.FindOneById(ObjectId.Parse(id));

user["firstname"] = userToEdit.FirstName;
user["lastname"] = userToEdit.LastName;
user["age"] = userToEdit.Age;

// Update user object
users.Save(user);

ID 值是一种特殊类型的字段,由数据库本身创建,以确保每个文档的唯一性,因此可以轻松获取文档。ID 值实际上包含一个字符串值,如 4ea41ac244b8681c3072b212,因此可以轻松地通过每次请求传递此值。

FindOneById 方法接收一个 BsonValue。为了将 ID 值作为 BsonValue 传递,我们调用 ObjectId.Parse 来获取 ID 值适合的 BsonValue 格式。

最后,我们调用 Save 来更新编辑后的文档。

插入

添加新文档和编辑文档一样简单。您创建一个集合的引用,创建一个新的 BsonDocument,并通过调用 insert 将其添加到集合引用中。

// Get user collection reference
var users = database.GetCollection("users");

// Create BsonDocument object for new user
var user = new BsonDocument();
user["firstname"] = userToEdit.FirstName;
user["lastname"] = userToEdit.LastName;
user["age"] = userToEdit.Age;
user["createdate"] = DateTime.Now;

// Insert new user object to collection
users.Insert(user);

动态模式

到目前为止,我们考虑了基本对象,并对它们进行了 CRUD 操作。正如您所见,我们还没有定义任何特定的模式设置。当我们在 BsonDocument 中设置一个值时,字段键会根据给定值的类型自动创建。在以下情况下,当我们执行以下行时:

user["age"] = 18;

age 键会自动创建,字段类型将是 Int32。您还可以通过调用对象的 Contains 方法来检查键是否存在,并确保它与给定类型兼容并且可以正确转换,例如:

if (user.Contains("updatedate") && user["updatedate"].IsDateTime)
{
    var updatedate = user["updatedate"].AsDateTime;
}

我提到了动态模式,我想让我的用户对象更具动态性。

[HttpPost]
public ActionResult Index(string id, string newRemark)
{
    var users = database.GetCollection("users");
    var user = users.FindOneById(ObjectId.Parse(id));

    var remark = new BsonDocument().
                        Add("content", newRemark).
                        Add("date", DateTime.Now);

    if (user.Contains("remarks"))
    {
        user["remarks"].AsBsonArray.Add(BsonValue.Create(remark));
    }
    else
    {
        user["remarks"] = new BsonArray().Add(BsonValue.Create(remark));
    }

    users.Save(user);

    return RedirectToAction("Index", new { id = id });
}

在这些行中,我们更改了用户对象。我们提出了新的数据类型 remarks

首先,我们检查用户对象是否已包含键为 remarks 的元素。remarks 实际上是一个数组,其中包含 contentdate 值。如果 remarks 存在,我们将其转换为数组并添加一条新备注。否则,我们创建一个新的数组类型并添加新备注。仅此而已。用户对象的输出将是这样的:

{ 
    "_id" : ObjectId("4ea51941073d601758138560"), 
    "firstname" : "ercan", 
    "lastname" : "anlama", 
    "age" : 26, 
    "createdate" : ISODate("2011-10-24T07:52:33.29Z"), 
    "remarks" : 
        [
            { 
                "content" : "this is my first remark", 
                "date" : ISODate("2011-10-24T07:53:22.511Z") 
            }
        ] 
}

对象序列化

驱动程序支持对象的序列化为文档。这意味着您不需要使用字符串值来访问字段和值,而是可以使用强类型值。让我们实际看看。

我们有两个对象:UserRemark

public class User
{
    public User()
    {
        Remarks = new List<Remark>();
    }

    public ObjectId id { get; set; }
    [BsonElementAttribute("firstname")]
    public string FirstName { get; set; }
    [BsonElementAttribute("lastname")]
    public string LastName { get; set; }
    [BsonElementAttribute("age")]
    public int Age { get; set; }
    [BsonElementAttribute("createdate")]
    public DateTime CreateDate { get; set; }
    [BsonElementAttribute("remarks")]
    public IList<Remark> Remarks { get; set; }

    public string GetFullName()
    {
        return String.Format("{0} {1}", FirstName, LastName);
    }
}

public class Remark
{
    [BsonElementAttribute("content")]
    public string RemarkContent;
    [BsonElementAttribute("date")]
    public DateTime Date; 
}

我们使用 BsonAttribute 来指定对象中的哪个属性与 BsonDocument 中的哪个字段匹配。另外,请注意,我们定义了一个特殊的属性,即 ObjectId 类型,用于存储 BsonDocument 的 ID 值。如果属性名称与字段键相同,则无需指定任何属性,就像我们在 id 属性中所做的那样。

以下是实现此序列化的方法:

var user = database.GetCollection("users").FindOneByIdAs<User>(ObjectId.Parse(id));

驱动程序使用以 As 结尾的方法。通常,这些方法用于以强类型格式检索文档。因此,我们可以保持 NoSQL 数据与面向对象之间的桥梁。

最后的寄语

我试图在本文中介绍 MongoDB 是什么以及如何使用官方 C# 驱动程序。当然,这些只是基本内容,但却是 MongoDB 最常用的功能,所以它比本文所展示的要广泛得多。它提供了强大的功能,如 GridFS 和 MapReduce,您在开发 MongoDB 项目的某些领域可能需要用到它们。

© . All rights reserved.