【NOSQL】非關係型數據庫MongoDB ( 用MongoDB的文檔結構描述數據關係 )

MongoDB的集合(collection)可以看做關係型數據庫的表,文檔對象(document)可以看做關係型數據庫的一條記錄。但兩者並不完全對等。表的結構是固定的,MongoDB集合並沒有這個約束;另外,存入集合的文檔對象甚至可以嵌入子文檔,或者“子集合”。他們最終都可以用類似於BJSON的格式描述。我們今天就來分析MongoDB這一特性帶來的獨特數據管理方式。我們還是以samus驅動爲例來分析,samus驅動支持兩種方式訪問數據庫,基本方式和linq方式,基本方式在上篇以介紹過,linq方式我不想單獨講解應用實例,這篇我會用兩種方式來對比介紹。

一、包含子文檔的集合操作

  有這麼一個應用場景,某網站提供會員登錄的功能,用戶需要註冊賬號才能享受會員服務,但是註冊者可能會因爲用戶資料表單輸入項過大而放棄填寫,因此用戶信息分爲主要資料和詳細資料兩項,初次註冊只需要填寫主要資料就行了。我們打算把詳細信息設計爲子文檔存儲。

   1) linq方式實現

  1. 新建數據描述類,描述用戶信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/// <summary>
/// 用戶主要資料
/// </summary>
public class UserInfo
{
    public string UserId { get; set; }
    public string UserName { get; set; }
    public string PassWord { get; set; }
    public Detail Detail { get; set; }
}
 
/// <summary>
/// 用戶詳細資料
/// </summary>
public class Detail
{
    public string Address { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

  2. 我們要新建一個用戶業務操作類“UserBLL”。這個時候要讓驅動知道UserInfo類描述了“用戶資料”的字段信息,在GetMongo()方法實現了配置步驟,UserBLL完整代碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class UserBLL
{
    public string connectionString = "mongodb://localhost";
    public string databaseName = "myDatabase";
 
    private Mongo mongo;
    private MongoDatabase mongoDatabase;
 
    //注意這裏泛型類型爲“UserInfo”
    private MongoCollection<UserInfo> mongoCollection;
 
    public UserBLL()
    {
        mongo = GetMongo();
        mongoDatabase = mongo.GetDatabase(databaseName) as MongoDatabase;
        mongoCollection = mongoDatabase.GetCollection<UserInfo>() as MongoCollection<UserInfo>;
        mongo.Connect();
    }
    ~UserBLL()
    {
        mongo.Disconnect();
    }
 
    /// <summary>
    /// 配置Mongo,將類UserInfo映射到集合
    /// </summary>
    private Mongo GetMongo()
    {
        var config = new MongoConfigurationBuilder();
        config.Mapping(mapping =>
        {
            mapping.DefaultProfile(profile =>
            {
                profile.SubClassesAre(t => t.IsSubclassOf(typeof(UserInfo)));
            });
            mapping.Map<UserInfo>();
        });
        config.ConnectionString(connectionString);
        return new Mongo(config.BuildConfiguration());
    }
}

  3. 接着,在“UserBLL”類中定義一個方法“InsertSomeData()”來插入一些數據:

  4. 定義一個查找數據的方法“Select”,它將查找用戶詳細信息中,地址在湖北的全部用戶:

1
2
3
4
5
6
7
/// <summary>
/// 查詢詳細資料地址爲湖北的用戶信息
/// </summary>
public List<UserInfo> Select()
{
    return mongoCollection.Linq().Where(x => x.Detail.Address == "湖北").ToList();
}

  5. 還定義一個刪除數據的方法,將刪除集合全部數據:

1
2
3
4
5
6
7
/// <summary>
/// 刪除全部用戶信息
/// </summary>
public void DeleteAll()
{
    mongoCollection.Remove(x => true);
}

  6. 在Main方法中添加如下代碼:

1
2
3
4
5
6
7
8
9
10
11
12
static void Main(string[] args)
{
 
    UserBLL userBll = new UserBLL();
    userBll.InsertSomeData();
    var users = userBll.Select();
    foreach (var user in users)
    {
        Console.WriteLine(user.UserName + "是湖北人");
    };
    userBll.DeleteAll();
}

  7. 最後執行程序,打印如下信息:

李四是湖北人
趙六是湖北人

   1) 普通實現

  普通方式實現不想多講,直接貼代碼,看看與linq方式有什麼區別:

  最後,我們通過這段代碼輸出全部用戶資料信息的BJSON格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/// <summary>
/// 打印數據BJSON
/// </summary>
public void PrintBJSON()
{
    string BJSON = string.Empty;
    foreach (var documet in mongoCollection.FindAll().Documents)
    {
 
        BJSON += documet.ToString();
 
    }
    Console.WriteLine(BJSON);
}

  結果如下:

1
2
3
4
{ "UserId": "1001", "UserName": "張三", "PassWord": "123456", "_id": "4d80ec1ab8a4731338000001" }
{ "UserId": "1002", "UserName": "李四", "PassWord": "123456", "Detail": { "Address": "湖北", "Age": 20, "Email": "[email protected]" }, "_id": "4d80ec1ab8a4731338000002" }
{ "UserId": "1003", "UserName": "王五", "PassWord": "123456", "Detail": { "Address": "廣東", "Age": 20, "Email": "[email protected]" }, "_id": "4d80ec1ab8a4731338000003" }
{ "UserId": "1004", "UserName": "趙六", "PassWord": "123456", "Detail": { "Address": "湖北" }, "_id": "4d80ec1ab8a4731338000004" }

二、包含“子集合”的集合操作

  同樣舉個例子:有一個學校人事管理系統要統計班級和學生的信息,現在定義了一個“班級集合”,這個集合裏面的學生字段是一個“學生集合”,包含了本班全部學生。

   1) linq方式實現

  基礎配置我就不多說了,數據類定義如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/// <summary>
/// 班級信息
/// </summary>
public class ClassInfo
{
    public string ClassName { get; set; }
    public List<Student> Students { get; set; }
}
 
/// <summary>
/// 學生信息
/// </summary>
public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }
}

  查詢叫“張三”的學生在哪個班級,以及他的詳細信息:

(這裏其實是ToList後在內存中查的,linq方式直接查詢好像驅動不支持。)

1
2
3
4
public List<ClassInfo> Select()
{
    return mongoCollection.Linq().ToList().Where(x => x.Students.Exists(s => s.Name == "張三")).ToList();
}

   1) 普通實現

  查詢叫“張三”的學生在哪個班級,以及他的詳細信息:

1
2
3
4
5
public List<Document> Select()
{
    var mongocollection = mongoDatabase.GetCollection("ClassInfo");
    return mongocollection.Find(new Document { { "Students.Name", "張三" } }).Documents.ToList();
}

  打印數據的BJSON:

1
2
3
{ "_id": "4d814bae5c5f000000005f63", "ClassName": "1001", "Students": [ { "Name": "張三", "Age": 10 }, { "Name": "李四", "Age": 0 } ] }
{ "_id": "4d814bae5c5f000000005f64", "ClassName": "1002", "Students": [ ] }
{ "_id": "4d814bae5c5f000000005f65", "ClassName": "1003", "Students": [ { "Name": "王五", "Age": 11 }, { "Name": "趙六", "Age": 9 } ] }

三、小結

  通過本節例子我們發現,MongoDB有它獨特的文檔結構可以描述數據對象之間的一些關係特徵。它雖然沒有關係型數據庫多表符合查詢那樣強大的表間查詢方式,但也可以通過文檔結構描述更靈活的關係特性,可以這麼說,關係型數據庫能做的,MongoDB基本上也可以做到。甚至有些關係數據庫不容易做到的,MongoDB也可以輕鬆做到,比如,描述數據類的繼承關係等。

作者:李盼(Lipan)
出處:[Lipan]http://www.cnblogs.com/lipan/
版權聲明:本文的版權歸作者與博客園共有。轉載時須註明本文的詳細鏈接,否則作者將保留追究其法律責任。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章