MongoDB use of the. NET Platform

Source: Internet
Author: User

website: http://www.cnblogs.com/skychen1218/p/6595759.html Preface

Recently took a little time to play the next mongodb.driver, to encapsulate the tool library, usually will often use MongoDB, so write an article combing knowledge at the same time to share their own results to everyone.

This article will be designed to resolve the lambda expression, interested students also look at my previous written " expression tree parsing ."

The article will give the source code at the end.

About MongoDB

MongoDB is a non-relational database based on distributed file storage, which supports complex queries compared to other nosql.

Text is a JSON-like Bson format that Bson evolved on the basis of JSON: faster traversal, easier operation, and more data types. MongoDB can therefore store more complex data types and also support indexing.

The concept of MongoDB is:

    • Database (library)
    • Collections (collection), a table similar to a relational database
    • Document, a piece of data similar to a relational database

  

MongoDB Pros and cons
    • Advantages
    1. High efficiency, built-in GRIDFS for massive data storage and fast range queries for large data sets.
    2. High scalability, sharding enables MongoDB to have higher throughput, replication makes MongoDB higher availability.
    3. Bson documents, easy to understand, view,
    4. Free
    • Disadvantages
    1. Transaction not supported
    2. Table Association not supported
    3. No CPU consumption, but memory consumption
    4. No Mature management Tools
MongoDB Usage Scenarios

Having the characteristics of efficient storage, allowing MongoDB to be used in operational logging is a very popular practice.

With the release of the upgrade to provide more powerful features, the product gradually matured in the main business is also many, such as the e-commerce order system and tracking module, a large number of main orders and order details, package status change information.

However, due to the way the Bson documents are stored, the usual development thinking patterns are changed. For a chestnut, traditional relational database, the order module will be divided into the main order table and the order list, the creation of the order will use the transaction to add two tables of data, find the order will also be linked through two tables query. However, using MongoDB, the Master Order table and its details will be saved as a document with a complete object.

It is also more suitable for use as a complete business module because it does not support transaction and Table Association.

Some friends have a problem with a non-relational database and relational database which is better. I think, no one can replace who, under normal circumstances, non-relational database more as a relational database extension, with good results, misuse will only be difficult.

  

MongoDB Installation

Originally wanted to write, the corresponding article in the garden too much, borrow a man's blog, portal

Mongodb:https://www.mongodb.com/download-center#community

Management tools: Robomongo, Portal

Use of Mongodb.driver

  

Create a console to download Mongodb.driver to NuGet. Write the following code:

Using System;
Using FrameWork.MongoDB.MongoDbConfig;
Using MongoDB.Bson.Serialization.Attributes;
Using Mongodb.driver;

Namespace FrameWork.MongoDb.Demo
{
Class Program
{
static void Main (string[] args)
{
var database = "Testdatabase";
var collection = "Testmongo";
var db = new Mongoclient ("Your Address"). Getdatabase (database);
var coll = db. Getcollection<testmongo> (collection);

var entity = new Testmongo
{
Name = "Skychen",
Amount = 100,
Createdatetime = DateTime.Now
};

Coll. Insertoneasync (entity). Configureawait (FALSE);

}
}

public class Testmongo:mongoentity
{

[Bsondatetimeoptions (Kind = datetimekind.local)]
Public DateTime createdatetime {get; set;}

Public decimal Amount {get; set;}

public string Name {get; set;}

}
}

The first demo: adding data is done. F12 can see imongocollection this interface, additions and deletions to check all have, note one and many. The use of the foundation is not too much, the code at the end of the article has provided additions and deletions to check the package.

The package of additions and deletions is relatively simple, but the update provided by Mongodb.driver is slightly more special. Through Builders<t>. Update.set (_fieldname, value) updates the specified field name, with multiple field names to be modified, via new updatedefinitionbuilder<t> (). Combine (updatedefinitionlist) to complete

However, this approach does not apply to our actual development, so the update method needs to be encapsulated with the entity update package and the Lambda update .

Entity Update encapsulation

Updating an entire entity with an ID as a filter is often done in practice. Since the ID is used as a condition, only one data can be updated with updateoneasync constraints. The updated field can traverse properties by reflecting the entity object. Below is the implementation code:

<summary>
MongoDB extension method
</summary>
Internal Static class Mongodbextension
{
<summary>
Get update information
</summary>
<typeparam name= "T" ></typeparam>
<param name= "entity" ></param>
<returns></returns>
Internal static updatedefinition<t> getupdatedefinition<t> (this T entity)
{
var properties = typeof (T). GetProperties (BindingFlags.Instance | BindingFlags.Public);

var updatedefinitionlist = getupdatedefinitionlist<t> (properties, entity);

var updatedefinitionbuilder = new updatedefinitionbuilder<t> (). Combine (updatedefinitionlist);

return updatedefinitionbuilder;
}

<summary>
Get update information
</summary>
<typeparam name= "T" ></typeparam>
<param name= "Propertyinfos" ></param>
<param name= "entity" ></param>
<returns></returns>
Internal static list<updatedefinition<t>> getupdatedefinitionlist<t> (propertyinfo[] Propertyinfos, object entity)
{
var updatedefinitionlist = new list<updatedefinition<t>> ();

Propertyinfos = Propertyinfos.where (A = a.name! = "_id"). ToArray ();

foreach (Var propertyInfo in Propertyinfos)
{
if (PropertyInfo.PropertyType.IsArray | | | typeof (IList). IsAssignableFrom (Propertyinfo.propertytype))
{
var value = Propertyinfo.getvalue (entity) as IList;

var filedname = Propertyinfo.name;

Updatedefinitionlist.add (BUILDERS<T>. Update.set (Filedname, value));
}
Else
{
var value = Propertyinfo.getvalue (entity);
if (Propertyinfo.propertytype = = typeof (decimal))
Value = value. ToString ();

var filedname = Propertyinfo.name;

Updatedefinitionlist.add (BUILDERS<T>. Update.set (Filedname, value));
}
}

return updatedefinitionlist;
}
}

Lambda Expression Update encapsulation

It has been used by other Orm to understand that lambda expressions are used very frequently, and Mongodb.driver already supports the filter conditions of lambda expressions, but does not support partial field updates, so we write the parsing ourselves. Below is the actual code:

#region MONGO Update Field expression resolution
<summary>
MONGO Update Field expression resolution
</summary>
<typeparam name= "T" ></typeparam>
public class Mongodbexpression<t>: ExpressionVisitor
{
#region member variables
<summary>
Update list
</summary>
Internal list<updatedefinition<t>> updatedefinitionlist = new list<updatedefinition<t>> ();
private string _fieldname;

#endregion

#region get the list of updates
<summary>
Get the list of updates
</summary>
<param name= "expression" ></param>
<returns></returns>
public static list<updatedefinition<t>> getupdatedefinition (Expression<func<t, T>> Expression
{
var mongoDb = new mongodbexpression<t> ();

Mongodb.resolve (expression);
return mongodb.updatedefinitionlist;
}
#endregion

#region parsing An expression
<summary>
Parsing an expression
</summary>
<param name= "expression" ></param>
private void Resolve (Expression<func<t, t>> Expression)
{
Visit (expression);
}
#endregion

#region accessing an object initialization expression

<summary>
Accessing an object initialization expression
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression Visitmemberinit (memberinitexpression node)
{
var bingdings = node. Bindings;

foreach (var item in bingdings)
{
var memberassignment = (memberassignment) item;
_fieldname = Item. Member.name;

if (MemberAssignment.Expression.NodeType = = Expressiontype.memberinit)
{
var lambda = expression.lambda<func<object>> (Expression.convert (Memberassignment.expression, typeof ( object));
var value = Lambda.compile (). Invoke ();
Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, value));
}
Else
{
Visit (memberassignment.expression);
}
}
return node;
}

#endregion

#region accessing two-tuple expressions

<summary>
Accessing the two-tuple expression
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression VisitBinary (binaryexpression node)
{
Updatedefinition<t> updatedefinition;

var value = ((constantexpression) node. right). Value;
if (node. Type = = typeof (int))
{
var realvalue = (int) value;
if (node. NodeType = = expressiontype.decrement)
Realvalue =-realvalue;

Updatedefinition = Builders<t>. Update.inc (_fieldname, Realvalue);
}
else if (node. Type = = typeof (Long))
{
var realvalue = (long) value;
if (node. NodeType = = expressiontype.decrement)
Realvalue =-realvalue;

Updatedefinition = Builders<t>. Update.inc (_fieldname, Realvalue);
}
else if (node. Type = = typeof (Double))
{
var realvalue = (double) value;
if (node. NodeType = = expressiontype.decrement)
Realvalue =-realvalue;

Updatedefinition = Builders<t>. Update.inc (_fieldname, Realvalue);
}
else if (node. Type = = typeof (decimal))
{
var realvalue = (decimal) value;
if (node. NodeType = = expressiontype.decrement)
Realvalue =-realvalue;

Updatedefinition = Builders<t>. Update.inc (_fieldname, Realvalue);
}
else if (node. Type = = typeof (float))
{
var realvalue = (float) value;
if (node. NodeType = = expressiontype.decrement)
Realvalue =-realvalue;

Updatedefinition = Builders<t>. Update.inc (_fieldname, Realvalue);
}
Else
{
throw new Exception (_fieldname + "does not support this type of operation");
}

Updatedefinitionlist.add (updatedefinition);

return node;
}
#endregion

#region Accessing array expressions

<summary>
Accessing array expressions
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression Visitnewarray (newarrayexpression node)
{
var listlambda = expression.lambda<func<ilist>> (node);
var list = Listlambda.compile (). Invoke ();
Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, list));

return node;
}

<summary>
Accessing a collection expression
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression Visitlistinit (listinitexpression node)
{
var listlambda = expression.lambda<func<ilist>> (node);
var list = Listlambda.compile (). Invoke ();
Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, list));

return node;
}
#endregion

#region Access constant expressions

<summary>
accessing constant expressions
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression Visitconstant (constantexpression node)
{
var value = node. Type.isenum? (int) node. Value:node. Value;

Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, value));

return node;
}
#endregion

#region Access Member expressions

<summary>
Accessing member expressions
</summary>
<param name= "Node" ></param>
<returns></returns>
protected override Expression Visitmember (memberexpression node)
{
if (node. Type.getinterfaces (). Any (a = A.name = = "IList"))
{
var lambda = expression.lambda<func<ilist>> (node);
var value = Lambda.compile (). Invoke ();

Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, value));
}
Else
{
var lambda = expression.lambda<func<object>> (Expression.convert (node, typeof (object)));
var value = Lambda.compile (). Invoke ();

if (node. Type.isenum)
Value = (int) value;

Updatedefinitionlist.add (BUILDERS<T>. Update.set (_fieldname, value));
}

return node;
}
#endregion
}
#endregion

Parsing an expression tree

For the encapsulation of lambda expressions, I'll focus on that. If there is an update code like this:

New Mongodbservice (). Update<user> (A = a._id = = "D99ce40d7a0b49768b74735b91f2aa75", a = new User            {                AddressList = new List <string>                {                    "number1",                    "Number2"                }, age                = ten,                birthdatetime = DateTime.Now,                Name = "Skychen",                numlist = new list<int>                {                    1211,23344                },                Sex = Sex.woman,                Son = new user< c15/>{                    Name = "Xiaochenpi", age                    = 1                }            });

So, we can debug the monitoring to see (), we can draw two important information:

1.expression<func<t, t>> parse out the body of the NodeType is Memberinit

There is a field information that needs to be modified in 2.Bindings.

And then debug it. Take a look at the first item in bindings, and we can learn a few important information.

The element in 1.Bindings is the memberassignment type.

2.Member can take the name attribute, which is the field name

3.Expression properties, using Expression.lambda, for compile (). Invoke () will get the value we need.

Both filename and value can be taken, so the update will solve it naturally.

is part of the source code, oddly, I did not traverse the visitmemberinit in the bindings after the Update.set, but the item's expression property once again access. That's because I need to deal with different types of data. For example:

Constant, I can define an object value to go to receive, and if I encounter an enumeration I need to strongly turn into an integer type.

Sets and arrays, if you use the object type hastily, object value = expression.lambda<func<object>> (node). Compile (). Invoke (), then the update to MongoDB will have a bug, strange _t,_v will appear. In this way I need to define the IList in order to solve this problem.

In addition, the work will also encounter the amount or the number of self-increase situation. Amount = A.amount+9.9m,count =a. Count-1. Mongodb.driver provided the Builders<t>. The Update.inc method is therefore overridden to encapsulate a two-tuple expression.

Additional

After testing, the official drive 2.4.3 and the 2.4.4 version have problems with the type IList support, such as, so now the package version supports up to 2.4.2.

  

End

Do not know how many friends directly dragged to the end of the article directly download the source ...

If it works for you, please recommend it.

In addition to thank the non-Big brother, the first to do my little mouse gave me a valuable bug, or I really dare not release the source code.

If there are any questions and suggestions, you can comment below, I will reply in time.

Hands on the source: Https://github.com/SkyChenSky/Framework.MongoDB.git

MongoDB use of the. NET Platform

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.