在本练习中,我们将向名为moviesDb
的数据库中插入一些数据。由于我们将研究两种插入数据的方式,我们将把数据存储到两个集合中(基于 T2 的对象的movies_bson
和基于概念验证模型的数据的movies_poco
)。从技术上来说,一旦保存数据,应该没有区别。
为了做到这一点,我们需要一些样本数据,如GetBsonMovies()
方法中所定义的,该方法返回一个BsonDocuments
数组。
代码清单 78:返回一个电影的文档数组
public static BsonDocument[] GetBsonMovies()
{
BsonDocument sevenSamurai = new BsonDocument()
{
{ "name" , "The Seven Samurai" },
{ "directorName" , " Akira Kurosawa" },
{ "actors", new BsonArray {
new BsonDocument("name", "Toshiro Mifune"),
new BsonDocument("name", "Takashi Shimura")}},
{ "year" , 1954 }
};
BsonDocument theGodfather = new BsonDocument()
{
{ "name" , "The Godfather" },
{ "directorName" , "Francis Ford Coppola" },
{ "actors", new BsonArray {
new BsonDocument("name", "Marlon Brando"),
new BsonDocument("name", "Al Pacino"),
new BsonDocument("name", "James Caan")} },
{ "year" , 1972 }
};
return new BsonDocument[] { sevenSamurai, theGodfather };
}
我们可以使用集合级别的InsertMany
或InsertManyAsync
方法插入数据。GetDatabaseReference
方法已经在前面提到过了,这只是一个自动引用数据库的辅助方法。
在插入一个文档的情况下,我们将使用InsertOne
或InsertOneAsync
方法,与上述方法相反。
代码清单 79:将电影插入数据库
public static async Task Insert<T>(T[] movies, string dbName, string tableName)
{
var db = DatabaseHelper.GetDatabaseReference("localhost", dbName);
var moviesCollection = db.GetCollection<T>(tableName);
await moviesCollection.InsertManyAsync(movies);
}
insert
方法是接受不同种类的movie
数组的通用方法,因为我们将使用相同的方法发送基于 POCO 对象的电影列表。
| | 提示:在 MongoDB C# 驱动程序中使用任何方法的一般规则是使用异步方法(如果可用),而不是同步方法。这本书可能并不总是遵循这个规则。 |
我们将Insert
方法称为:
代码清单 80:调用插入方法
BsonDocument[] movies = MovieManager.GetBsonMovies();
MovieManager.Insert<BsonDocument>(movies, "moviesDb", "movies_bson").Wait();
不要被MovieManager
类所迷惑,它是作为一个辅助类创建的,包含方法GetBsonMovies
和Insert<T>(..)
。
运行此代码后,查询movies_bson
集合时,结果如下。
图 42 存储在数据库中的 Bson 格式的电影
正如我们之前看到的那样,BsonDocument
的替代方法是使用POCO
类来表示对象,在这种情况下,我们将首先声明一个Movie
对象的数组。
代码清单 81 获取电影列表作为数组
public static Movie[] GetMovieList()
{
Movie sevenSamurai = new Movie()
{
Name = "Seven Samurai",
Director = "Akira Kurosawa",
Year = 1954,
Actors = new Actor[]
{
new Actor {Name = "Toshiro Mifune"},
new Actor {Name = "Takashi Shimura"},
}
};
Movie theGodFather = new Movie()
{
Name = "The Godfather",
Director = "Francis Ford Coppola",
Year = 1972,
Actors = new Actor[]
{
new Actor {Name = "Marlon Brando"},
new Actor {Name = "Al Pacino"},
},
Metadata = new BsonDocument("href", "http://thegodfather.com")
};
return new Movie[] { sevenSamurai, theGodFather };
}
但是,在调用Insert<Movie>()
方法之前,正如我们之前看到的,我们需要调用RegisterClassMap
,这将使驱动程序知道 POCO 对象和所需序列化之间的映射。映射器的完整代码和insert
方法的调用如下。
代码清单 82:完整的对象到 BSON 映射
public class BsonMapper
{
public static void Map()
{
if (!BsonClassMap.IsClassMapRegistered(typeof(Movie)))
{
BsonClassMap.RegisterClassMap<Movie>(movie =>
{
movie.MapIdProperty(p => p.MovieId)
.SetIdGenerator(new StringObjectIdGenerator());
movie.MapProperty(p => p.Name).SetElementName("name");
movie.MapProperty(p => p.Director).SetElementName("directorName");
movie.MapProperty(p => p.Year).SetElementName("year");
movie.MapProperty(p => p.Actors).SetElementName("actors");
movie.UnmapProperty(p => p.Age);
movie.MapExtraElementsMember(p => p.Metadata);
movie.SetIgnoreExtraElements(true);
});
}
if (!BsonClassMap.IsClassMapRegistered(typeof(Actor)))
{
BsonClassMap.RegisterClassMap<Actor>(actor =>
{
actor.MapProperty(p => p.Name).SetElementName("name");
});
}
}
}
从调用者的角度来看,代码是什么样的?
代码清单 83:使用概念验证类映射插入电影
private static void Main(string[] args)
{
Movie[] movies = MovieManager.GetMovieList();
BsonMapper.Map(); //map the class to the MongoDB representation.
MovieManager.Insert<Movie>(movies, "moviesDb", "movies_poco").Wait();
}
为了有所作为,我们将数据存储到movies_poco
集合中。这纯粹是为了展示功能。这两种方法是相同的,在生产系统中,我们将使用相同的集合。
我们也来关注一下bson mape。Map() 调用。这应该只在应用启动时执行一次。
插入两部电影的结果如下。结论是两种方法得到的结果完全相同。
图 43:插入数据库的电影。