添加dll引用

运行nuget命令:Install-Package mongocsharpdriver

即可安装MongoDb与C#相关的dll,主要有下面这4个dll。

Repository数据访问设计

1,BaseMongoDB

主要封装了连接数据库,获取数据库和获取集合的操作,如下代码。

namespace XXX.Frameworks.MongoDb.Repository
{
    /// <summary>
    /// MongoDb基类
    /// 主要封装了创建数据库连接,获取数据库和获取集合的操作
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class BaseMongoDB<T> where T : class
    {
        public BaseMongoDB(string connectionString)
            : this(connectionString, null)
        {
        }
        
        public BaseMongoDB(string connectionString, string collectionName)
        {
            if (connectionString.IsNullOrEmpty())
            {
                connectionString = ConfigurationManager.ConnectionStrings["MongoTicketDB"].ConnectionString;
            }

            if (connectionString.IsNullOrEmpty())
            {
                throw new Exception("mongodb connectionString can not be empty!");
            }

            var mongoUrl = new MongoUrl(connectionString);
            DB = GetDatabaseFromUrl(mongoUrl);
            if (!string.IsNullOrEmpty(collectionName))
            {
                CollectionName = collectionName;
                this.Collection = DB.GetCollection<T>(collectionName);
            }
        }

        /// <summary>
        /// 依据连接字符串获取数据库
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private IMongoDatabase GetDatabaseFromUrl(MongoUrl url)
        {
            var client = new MongoClient(url);
            var db = client.GetDatabase(url.DatabaseName);
            return db;
        }

        /// <summary>
        /// 集合
        /// </summary>
        public IMongoCollection<T> Collection { get; }

        /// <summary>
        /// 数据库
        /// </summary>
        public IMongoDatabase DB { get; }

        /// <summary>
        /// 集合名称,默认为空
        /// </summary>
        public string CollectionName { get; } = string.Empty;
    }
}

2,MongoRepository

主要封装了对数据库的常用操作,比如增,删,改和查等,如下代码。

namespace XXX.Frameworks.MongoDb.Repository
{
    /// <summary>
    /// MongoDb数据访问基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public class MongoRepository<T, TKey> : BaseMongoDB<T> where T : class
    {
        private readonly Type _keyType;

        protected MongoRepository(string connectionString = "", string collectionName = "")
            : base(connectionString, GetCollectionName(collectionName))
        {
            _keyType = typeof(TKey);
            if (_keyType != typeof(string) && _keyType != typeof(long) && _keyType != typeof(ObjectId))
            {
                throw new Exception("TKey must these type: string or long or ObjectId");
            }

            Initial();
        }

        /// <summary>
        /// 初始化
        /// 注册序列化器
        /// </summary>
        private void Initial()
        {
            try
            {
                var serializer = BsonSerializer.LookupSerializer(typeof(DateTime));
                if (serializer == null || serializer.GetType() != typeof(LocalTimeSerializer))
                {
                    // remove exist
                    var cacheFieldInfo = typeof(BsonSerializerRegistry).
                        GetField("_cache", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                    var _cacheTemp = cacheFieldInfo.GetValue(BsonSerializer.SerializerRegistry);
                    var _cache = _cacheTemp as ConcurrentDictionary<Type, IBsonSerializer>;
                    IBsonSerializer removeed;
                    _cache.TryRemove(typeof(DateTime), out removeed);

                    // add my owner
                    BsonSerializer.RegisterSerializer(typeof(DateTime), new LocalTimeSerializer());
                }
            }
            catch
            {
            }
        }

        /// <summary>
        /// 依据连接字符串创建数据库访问实例
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public static MongoRepository<T, TKey> CreateRepository(MongoDBs db = MongoDBs.MongoTicketDB)
        {
            var connStrName = Enum.GetName(typeof(MongoDBs), db);
            var connStr = ConfigurationManager.ConnectionStrings[connStrName].ConnectionString;
            return new MongoRepository<T, TKey>(connStr);
        }

        /// <summary>
        /// 获取集合名
        /// </summary>
        /// <param name="specifiedCollectionName"></param>
        /// <returns></returns>
        private static string GetCollectionName(string specifiedCollectionName)
        {
            string collectionName;

            if (!specifiedCollectionName.IsNullOrEmpty())
            {
                collectionName = specifiedCollectionName;
            }
            else
            {
                var att = Attribute.GetCustomAttribute(typeof(T), typeof(CollectionNameAttribute));
                collectionName = att != null ? ((CollectionNameAttribute)att).Name : typeof(T).Name;

                if (string.IsNullOrEmpty(collectionName))
                {
                    throw new ArgumentException("Collection name cannot be empty for this entity");
                }
            }

            return collectionName;
        }

        /// <summary>
        /// 判断集合是否存在
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public bool Exists(Expression<Func<T, bool>> predicate)
        {
            var count = this.Collection.Find(predicate).CountAsync().Result;
            return count > 0;
        }

        /// <summary>
        /// 依据id获取实体(文档)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public T GetById(TKey id)
        {
            var filter = Builders<T>.Filter.Eq("_id", id);
            var result = this.Collection.Find(filter).FirstOrDefaultAsync().Result;
            return result;
        }

        /// <summary>
        /// 查询所有实体
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> GetAll()
        {
            return this.Collection.Find(new BsonDocument()).ToListAsync().Result;
        }

        /// <summary>
        /// 依据查询表达式来查询实体
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public IEnumerable<T> GetBy(Expression<Func<T, bool>> predicate)
        {
            return this.Collection.Find(predicate).ToListAsync().Result;
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="predicate"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <returns></returns>
        public IEnumerable<T> GetByPaging(Expression<Func<T, bool>> predicate, int pageIndex, int pageSize, IList<OrderBy<T>> orderBy = null)
        {
            if (pageIndex < 1)
            {
                pageIndex = 1;
            }

            if (pageSize < 1)
            {
                pageSize = 15;
            }

            var data = this.Collection.Find(predicate);

            if (orderBy != null && orderBy.Count > 0)
            {
                var idx = 0;
                foreach (var sort in orderBy)
                {
                    idx++;
                    if (idx == 1)
                    {
                        data = sort.IsAscending ? data.SortBy(sort.Field) : data.SortByDescending(sort.Field);
                    }
                    else
                    {
                        var sortByData = data as IOrderedFindFluent<T, T>;
                        if (sortByData == null)
                        {
                            continue;
                        }

                        data = sort.IsAscending ? sortByData.ThenBy(sort.Field) : sortByData.ThenByDescending(sort.Field);
                    }
                }
            }

            var result = data.Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync().Result;

            return result;
        }

        /// <summary>
        /// 新增(单个)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public void Insert(T entity)
        {
            AsyncHelper.RunSync(() => this.Collection.InsertOneAsync(entity));
        }

        /// <summary>
        /// 新增(批量)
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public void Insert(IEnumerable<T> entities)
        {
            AsyncHelper.RunSync(() => this.Collection.InsertManyAsync(entities));
        }

        /// <summary>
        /// 新增,从json字符串
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public IList<BsonDocument> Insert(string json)
        {
            if (string.IsNullOrWhiteSpace(json))
            {
                return new List<BsonDocument>();
            }

            if (typeof(T) != typeof(BsonDocument))
            {
                throw new Exception("this method just for MogoRepository<BsonDocument> ");
            }

            var documents = new List<BsonDocument>();

            if (json.TrimStart().StartsWith("["))
            {
                var bsonDocument = BsonSerializer.Deserialize<BsonArray>(json);
                foreach (var b in bsonDocument)
                {
                    var bd = b.ToBsonDocument();
                    bd.Remove("$id");
                    documents.Add(bd);
                }
            }
            else
            {
                var bsonDocument = BsonSerializer.Deserialize<BsonDocument>(json);
                bsonDocument.Remove("$id");
                documents.Add(bsonDocument);
            }
            AsyncHelper.RunSync(()=> this.DB.GetCollection<BsonDocument>(this.CollectionName).InsertManyAsync(documents));

            return documents;
        }

        /// <summary>
        /// 更新(单个)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>返回影响的行数</returns>
        public long Update(T entity)
        {
            var filter = Builders<T>.Filter.Eq("_id", GetIdValue(entity));
            var replaceResult = this.Collection.ReplaceOneAsync(filter, entity).Result;
            return replaceResult.ModifiedCount;
        }

        /// <summary>
        /// 更新(批量)
        /// </summary>
        /// <param name="entities"></param>
        /// <returns></returns>
        public long Update(IEnumerable<T> entities)
        {
            long modifiedCount = 0;
            foreach (var entity in entities)
            {
                var filter = Builders<T>.Filter.Eq("_id", GetIdValue(entity));
                var replaceResult = this.Collection.ReplaceOneAsync(filter, entity).Result;
                modifiedCount += replaceResult.ModifiedCount;
            }

            return modifiedCount;
        }

        /// <summary>
        /// 更新,如果不存在则新增
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public bool UpdateOrAdd(T entity)
        {
            SaveBigDataToLog(entity);

            if (Update(entity) < 1)
            {
                this.Collection.InsertOneAsync(entity);
            }

            return true;
        }

        /// <summary>
        /// 更新(局部更新)
        /// </summary>
        /// <param name="query"></param>
        /// <param name="columnValues">指定字段</param>
        /// <returns></returns>
        public long Update(Expression<Func<T, bool>> query, Dictionary<string, object> columnValues)
        {
            if (columnValues == null || columnValues.Count == 0)
            {
                throw new ArgumentException("Update Columns is Null!", nameof(columnValues));
            }

            var fileter = Builders<T>.Filter.Where(query);
            var update = Builders<T>.Update;
            UpdateDefinition<T> updateDefinination = null;
            columnValues.Keys.ToList().ForEach(x =>
            {
                updateDefinination = updateDefinination == null ? update.Set(x, columnValues[x]) : updateDefinination.Set(x, columnValues[x]);
            });
            var result = this.Collection.UpdateManyAsync<T>(query, updateDefinination).Result;

            return result.ModifiedCount;
        }

        /// <summary>
        /// 依据id删除数据(文档)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public long Delete(TKey id)
        {
            var filter = Builders<T>.Filter.Eq("_id", id);
            var result = this.Collection.DeleteOneAsync(filter).Result;
            return result.DeletedCount;
        }

        /// <summary>
        /// 删除,依据实体
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public long Delete(T entity)
        {
            var filter = Builders<T>.Filter.Eq("_id", GetIdValue(entity));
            var result = this.Collection.DeleteOneAsync(filter).Result;
            return result.DeletedCount;
        }

        /// <summary>
        /// 删除,依据查询表达式
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        public long Delete(Expression<Func<T, bool>> predicate)
        {
            var result = this.Collection.DeleteManyAsync<T>(predicate).Result;
            return result.DeletedCount;
        }

        /// <summary>
        /// 删除所有
        /// </summary>
        /// <returns></returns>
        public void RemoveAll()
        {
            AsyncHelper.RunSync(()=> this.Collection.DeleteManyAsync(new BsonDocument()));
        }

        #region Private method

        /// <summary>
        /// 获取实体的id
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        private object GetIdValue(T entity)
        {
            object result = null;

            if (typeof(T).IsSubclassOf(typeof(BaseMongoEntity<TKey>)))
            {
                var baseEntity = entity as BaseMongoEntity<TKey>;
                result = baseEntity.Id;
            }
            else if (typeof(T) == typeof(BsonDocument))
            {
                var bson = entity as BsonDocument;
                var objectId = bson["_id"];
                if (objectId != null && objectId.IsObjectId)
                {
                    result = objectId.AsObjectId;
                }
            }

            if (result == null)
            {
                throw new Exception("can not get Id (or ObjectId) from the entity, please check!");
            }

            return result;
        }

        /// <summary>
        /// 记录日志
        /// </summary>
        /// <param name="entity"></param>
        private void SaveBigDataToLog(T entity)
        {
            try
            {
                var dataJson = entity.ToJson();

                var saveDirector = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "VLogs", "PackageFH");
                saveDirector = Path.Combine(saveDirector, "BigDataLog");
                saveDirector = Path.Combine(saveDirector, DateTime.Now.ToString("yyyyMMdd"));
                if (!Directory.Exists(saveDirector))
                {
                    Directory.CreateDirectory(saveDirector);
                }
                var fileName = Path.Combine(saveDirector, $"{typeof(T).Name}_{Guid.NewGuid()}");
                File.WriteAllText(fileName, dataJson);
            }
            catch
            {
            }
        }
        #endregion
    }
}

Entity实体设计

因为mongoDb集合的主键主要有string,int和ObjectId(mongodb内置类型)这几种类型,所以封装了包含字段Id的泛型类型,如下代码。

namespace XXX.Frameworks.MongoDb
{
    public interface IEntity<TKey>
    {
        TKey Id { get; set; }
    }
}
namespace XXX.Frameworks.MongoDb
{
    [DataContract(IsReference = true)]
    [Serializable]
    public abstract class BaseMongoEntity<TKey> : IEntity<TKey>
    {
        [DataMember]
        public TKey Id { get; set; }
    }
}
namespace XXX.Frameworks.MongoDb.Tests.Entity
{
    [DataContract(IsReference = true)]
    [Serializable]
    public class OrderLog: BaseMongoEntity<string>
    {
        [DataMember]
        public int OrderId { get; set; }

        [DataMember]
        public decimal OrderAmount { get; set; }

        [DataMember]
        public string Title { get; set; }

        [DataMember]
        public string Summary { get; set; }

        [DataMember]
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime? UpdatedDate { get; set; }

        [DataMember]
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime OrderDate { get; set; }
    }
}

需要注意的是,一般情形下,集合的主键就指定为默认的ObjectId类型,也可以手动指定为string和int类型。

posted on 2015-12-08 18:58  永远的麦子  阅读(3798)  评论(0编辑  收藏  举报