猿教程 Logo

.Net连接MongoDb:.NET驱动程序中的对象序列化

介绍

在上一篇文章中,我们开始使用MongoDb的.NET驱动程序。 我们开始构建一个简单的上下文类,作为我们的MongoDb数据库和集合的句柄。 它也将成为收藏中的文件的门户。 我们还测试了如何在代码中连接到MongoDb服务器。

在这篇文章中,我们将继续探索.NET驱动。 特别是我们将看到我们如何在C#代码中表示MongoDb文档。 我们将继续在上一篇文章中介绍的演示.NET项目。

MongoDb序列化

本主题是关于构建可以序列化为BSON文档并返回的C#对象。即 当我们构建一个C#对象时,我们可以确定它是如何序列化成MongoDb文件的。 同样的,序列化规则也指定BSON文档如何映射到C#对象。 保持简单,我们可以说如果Person对象具有Telephone属性,则可以在相应的BSON文档中用“phone”属性表示。

C#驱动程序将通过数据(de)序列化自动转换为BSON和C#对象。 默认的序列化非常简单。 说我们有以下POCO:

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
}

该POCO的默认JSON表示形式将是:

{
    "Name" : "Elvis"
    , "Address" : "Graceland"
}

POCO将以BSON格式保存,但上述JSON可以显示二进制源。 如果POCO有一些对象序列,例如:

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    IEnumerable<string> Telephones { get; set; }
}

它被翻译成一个JSON数组:

{
    "Name" : "Elvis"
    , "Address" : "Neverland"
    , "Telephones" : ["123", "456"]
}

嵌套对象如...

public class Customer
{
    public string Name { get; set; }
    public string Address { get; set; }
    IEnumerable<string> Telephones { get; set; }
    public WebPage PublicPage { get; set; }
}
 
public class WebPage
{
    public bool IsSsl { get; set; }
    public string Domain { get; set; }
}

...被表示为这样的嵌套文档:

{
    "Name" : "Elvis"
    , "Address" : "Neverland"
    , "Telephones" : ["123", "456"]
    , "PublicPage" : { "IsSsl": true, "Domain" : "company.com" }
}

你可能看到这里的模式。 C#对象的属性被转换成最接近的JSON表示形式。

更改默认的序列化

默认的序列化并不总是我们需要的。 例如 文件在演示餐厅集合。 像“行政区”和“美食”这样的属性应该更像是自治市镇和美食,遵循C#属性命名约定。 此外,文档属性可能会获得完全不同的名称。 也许我们不喜欢“restaurant_id”属性,并希望在我们的餐厅C#对象中简单地称之为“Id”。 还有许多其他注意事项,例如不同的数据类型,空值,缺少的属性。 例如。 整数可以作为文本中的字符串保存,但是我们希望将其作为C#中的Int32。

序列化映射规则通过C#代码中的各种MongoDb属性实现。 现在让我们来看看这些属性,看看餐厅文档如何被映射成C#对象。 在Repository文件夹中添加一个名为RestaurantDb的新类:

using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using Newtonsoft.Json;
using System.Collections.Generic;

namespace MongoDbDotNet.Repository
{
	[BsonIgnoreExtraElements]
	public class RestaurantDb
	{
		[BsonId]
		[BsonElement(elementName:"_id")]
		public ObjectId MongoDbId { get; set; }
		[BsonElement(elementName:"address")]
		public RestaurantAddressDb Address { get; set; }
		[BsonElement(elementName:"borough")]
		public string Borough { get; set; }
		[BsonElement(elementName: "cuisine")]
		public string Cuisine { get; set; }
		[BsonElement(elementName:"grades")]
		public IEnumerable<RestaurantGradeDb> Grades { get; set; }
		[BsonElement(elementName: "name")]
		public string Name { get; set; }
		[BsonElement(elementName:"restaurant_id")]
		[BsonRepresentation(BsonType.String)]
		public int Id { get; set; }

		public override string ToString()
		{
			return JsonConvert.SerializeObject(this, Formatting.Indented);
		}
	}
}

该类将不会编译,我们将添加一些丢失的对象。

您需要通过NuGet添加对Json.NET库的引用来编译此代码:


我们来看看每个属性的作用:

  • [BsonIgnoreExtraElements]:我们告诉序列化器忽略一个JSON文档中的元素,但是没有映射到C#对象中。 如果您直接在数据库中向文档添加新属性,这将非常有用

  • [BsonId]:我们声明这个属性是ID

  • [BsonElement(elementName:“_ id”)]:具有字符串输入的BsonElement属性是声明在对应的JSON文档中调用C#属性的方式。 换句话说,该属性使我们能够在JSON文档和相应的POCO中具有不同的属性名称

  • [BsonRepresentation(BsonType.String)]:使用此属性,我们声明C#属性类型与其BSON / JSON对应方不同。 餐厅集合中的餐厅ID存储为字符串。 但是,我们要将它们转换为整数。 请注意此属性,并确保您在大型文档样本上进行测试。 如果单个文档具有不同类型的restaurant_id,则数据反序列化将失败,并将抛出格式异常。

我们现在可以将缺少的成分添加到Repository文件夹中。 首先我们有RestaurantAddressDb类:

using MongoDB.Bson.Serialization.Attributes;

namespace MongoDbDotNet.Repository
{
	[BsonIgnoreExtraElements]
	public class RestaurantAddressDb
	{	
		[BsonElement(elementName: "building")]
		public string BuildingNr { get; set; }
		[BsonElement(elementName: "coord")]
		public double[] Coordinates { get; set; }
		[BsonElement(elementName: "street")]
		public string Street { get; set; }
		[BsonElement(elementName:"zipcode")]
		[BsonRepresentation(MongoDB.Bson.BsonType.String)]
		public int ZipCode { get; set; }
	}
}

还有一个RestaurantGradeDb类:

using MongoDB.Bson.Serialization.Attributes;
using System;

namespace MongoDbDotNet.Repository
{
	[BsonIgnoreExtraElements]
	public class RestaurantGradeDb
	{
		[BsonElement(elementName: "date")]
		public DateTime InsertedUtc { get; set; }
		[BsonElement(elementName: "grade")]
		public string Grade { get; set; }
		[BsonElement(elementName: "score")]
		public object Score { get; set; }
	}
}

Score属性是一个奇怪的,它是类型对象。 问题在于,并不是所有的分数都作为整数存储在数据库中。 其中一些是BSON类型的null。 以下是一个例子:

{
        "_id" : ObjectId("56edc2ff03a1cd840734f966"),
        "address" : {
                "building" : "725",
                "coord" : [
                        -74.01381169999999,
                        40.6336821
                ],
                "street" : "65 Street",
                "zipcode" : "11220"
        },
        "borough" : "Brooklyn",
        "cuisine" : "Other",
        "grades" : [
                {
                        "date" : ISODate("2015-01-20T00:00:00Z"),
                        "grade" : "Not Yet Graded",
                        "score" : null
                }
        ],
        "name" : "Swedish Football Club",
        "restaurant_id" : "41278206"
}

空类型不能转换为C#整数,所以我将分数声明为对象。

下一步是在我们的ModelContext类中的餐馆集合附近添加适当的句柄。 集合由C#中的通用IMongoCollection接口表示。 这里有更新的ModelContext类,其中有一个Restaurants属性,作为餐馆集合的句柄。 还有一些其他小的添加以及Create方法中的空检查逻辑:

using MongoDB.Driver;
using MongoDbDotNet.Infrastructure;
using System;

namespace MongoDbDotNet.Repository
{
	public class ModelContext
	{
		private IMongoClient Client { get; set; }
		private IMongoDatabase Database { get; set; }
		private IConfigurationRepository ConfigurationRepository { get; set; }
		private static ModelContext _modelContext;

		private ModelContext() { }

		public static ModelContext Create(IConfigurationRepository configurationRepository, 
			IConnectionStringRepository connectionStringRepository)
		{
			if (configurationRepository == null) throw new ArgumentNullException("ConfigurationRepository");
			if (connectionStringRepository == null) throw new ArgumentNullException("ConnectionStringRepository");
			if (_modelContext == null)
			{
				_modelContext = new ModelContext();
				string connectionString = connectionStringRepository.ReadConnectionString("MongoDb");
				_modelContext.Client = new MongoClient(connectionString);
				_modelContext.Database = _modelContext.Client.GetDatabase(configurationRepository.GetConfigurationValue("DemoDatabaseName", "model"));
				_modelContext.ConfigurationRepository = configurationRepository;
			}
			return _modelContext;
		}

		public void TestConnection()
		{
			var dbsCursor = _modelContext.Client.ListDatabases();
			var dbsList = dbsCursor.ToList();
			foreach (var db in dbsList)
			{
				Console.WriteLine(db);
			}
		}

		public IMongoCollection<RestaurantDb> Restaurants
		{
			get { return Database.GetCollection<RestaurantDb>(ConfigurationRepository.GetConfigurationValue("RestaurantsCollectionName", "restaurants")); }
		}
	}
}

我们来试试这个在Program.cs的Main方法。 以下代码示例将显示查询的示例。 不要担心它太多了,稍后我们将在.NET驱动程序中查看更详细的查询。 我们想筛选位于布鲁克林市的所有餐厅。 “餐厅”变量将包含所有的搜索结果,而“餐厅”只能保存一个值。 您将看到ToList和FirstOrDefault操作之间的差异,它们与LINQ中的集合相同:

using MongoDB.Driver;
using MongoDbDotNet.Infrastructure;
using MongoDbDotNet.Repository;
using System;

namespace MongoDbDotNet
{
	class Program
	{
		static void Main(string[] args)
		{
			ModelContext modelContext = ModelContext.Create(new ConfigFileConfigurationRepository(), new AppConfigConnectionStringRepository());
			var filter = Builders<RestaurantDb>.Filter.Eq(r => r.Borough, "Brooklyn");
			var restaurants = modelContext.Restaurants.FindSync<RestaurantDb>(filter).ToList();
			var restaurant = modelContext.Restaurants.FindSync<RestaurantDb>(filter).FirstOrDefault();
			Console.WriteLine(restaurant);

			Console.ReadKey();
		}
	}
}

如果需要,您可以添加一些遍历餐馆集合的代码。 否则,将在控制台中打印一个餐厅,类似于以下内容:

{
  "MongoDbId": "56edc2ff03a1cd840734dba8",
  "Address": {
    "BuildingNr": "2780",
    "Coordinates": [
      -73.982419999999991,
      40.579505
    ],
    "Street": "Stillwell Avenue",
    "ZipCode": 11224
  },
  "Borough": "Brooklyn",
  "Cuisine": "American ",
  "Grades": [
    {
      "InsertedUtc": "2014-06-10T00:00:00Z",
      "Grade": "A",
      "Score": 5
    },
    {
      "InsertedUtc": "2013-06-05T00:00:00Z",
      "Grade": "A",
      "Score": 7
    },
    {
      "InsertedUtc": "2012-04-13T00:00:00Z",
      "Grade": "A",
      "Score": 12
    },
    {
      "InsertedUtc": "2011-10-12T00:00:00Z",
      "Grade": "A",
      "Score": 12
    }
  ],
  "Name": "Riviera Caterer",
  "Id": 40356018
}

好的,我们已经在.NET中成功实现了一些基本的序列化。

我们将在下一篇文章中继续提供更多的序列化示例。


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CsharpMongo/14.html