MongoDB 系列(一) C# 類似EF語法簡單封裝


之前寫過一篇關於MongoDB的封裝 發現太過繁瑣 於是打算從新寫一篇簡易版

1:關於MongoDB的安裝請自行百度,進行權限認證的時候有一個小坑,3.0之后授權認證方式默認的SCRAM-SHA-1模式,

需要首先命令創建一個用戶,然后Drop掉這個用戶,然后修改system.version里的authScheam為3,在沒有創建用戶的情況下

authScheam的值貌似是查詢不到的。

修改成3后,授權驗證方式就變成了MONGODB-CR

 

 2:建立一個聚合根和實體

 public interface ICore
    {
        string Id { set; get; }
    }

    /// <summary>
    /// 聚合根
    /// </summary>
    public interface IAggregateRoot
    {
         string Id { set; get; }
    }

    /// <summary>
    /// 實體
    /// </summary>
    public abstract class Core : ICore
    {
        public string Id { set; get; } = Guid.NewGuid().ToString();
    }

3:建立實體

/// <summary>
    /// 用戶
    /// </summary>
    public class User : Core, IAggregateRoot
    {
        /// <summary>
        /// 名字
        /// </summary>
        public string Name { set; get; }

        /// <summary>
        /// 身份證
        /// </summary>
        public string Cardcertificate { set; get; }

        /// <summary>
        /// 性別
        /// </summary>
        public Gender Gender { set; get; } = Gender.Boy;

        /// <summary>
        /// 用戶的房屋信息
        /// </summary>
        public List<House> Houses { set; get; } = new List<House>();
    }


    public class House : Core
    {
        public string Adress { set; get; }
    }

    public enum Gender
    {
        Boy = 0,
        Gril = 1
    }

 

4:建立一個接口Context似於EF的DBContext

 

    public interface IMongoDBContext
    {
        

        /// <summary>
        /// 具體的表連接器
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <returns></returns>
       IMongoCollection<K> DbSet<K>() where K : IAggregateRoot;


    }

添加一個接口的實現

Client 表示的是Mongodb客戶端驅動鏈接 類似於ADO里的SqlConnection

DataBase 表示的是具體的數據庫

DbSet 指定具體的表

MongoCredential 認證授權的加密方式

3:建立一個具體的DBContext

BasicContext  類似於EF里面大家直接鏈接具體庫的DBContext

Users User表的映射

4:建立一個MongoDB訪問的擴展類

    public static class MongodbExpansion
    {
        /// <summary>
        /// 單個對象添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="entity"></param>
        public static void Add<T>(this IMongoCollection<T> collection, T entity) where T : IAggregateRoot
            => collection.InsertOne(entity);

        /// <summary>
        /// 集合添加
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="entitys"></param>
        public static void AddRange<T>(this IMongoCollection<T> collection, List<T> entitys) where T : IAggregateRoot
            => collection.InsertMany(entitys);


        /// <summary>
        /// entity mongodb需要更新的實體 properts需要更新的集合屬性,大小寫不限 默認更新整個對象 replace 默認空屬性不修改
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="entity">mongodb需要更新的實體</param>
        /// <param name="properts">需要更新的集合屬性,大小寫不限 默認更新整個對象 </param>
        /// <param name="replace">默認對象屬性為空時不替換當前值</param>
        public static void Update<T>(this IMongoCollection<T> collection, T entity, List<string> properts = null, bool replace = false) where T : IAggregateRoot
        {
            if (entity == null)
                throw new NullReferenceException();

            var type = entity.GetType();
            ///修改的屬性集合
            var list = new List<UpdateDefinition<T>>();

            foreach (var propert in type.GetProperties())
            {
                if (propert.Name.ToLower() != "id")
                {
                    if (properts == null || properts.Count < 1 || properts.Any(o => o.ToLower() == propert.Name.ToLower()))
                    {
                        var replaceValue = propert.GetValue(entity);
                        if (replaceValue != null)
                        {
                            list.Add(Builders<T>.Update.Set(propert.Name, replaceValue));
                        }
                        else if (replace)
                            list.Add(Builders<T>.Update.Set(propert.Name, replaceValue));
                    }
                }
            }
            #region 有可修改的屬性
            if (list.Count > 0)
            {
                ///合並多個修改//new List<UpdateDefinition<T>>() { Builders<T>.Update.Set("Name", "111") }
                var builders = Builders<T>.Update.Combine(list);
                ///執行提交修改
                collection.UpdateOne(o => o.Id == entity.Id, builders);
            }
            #endregion

        }

        /// <summary>
        /// 移除根據ID
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="entity"></param>
        public static void Remove<T>(this IMongoCollection<T> collection, T entity) where T : IAggregateRoot
        => collection.DeleteOne(o => o.Id == entity.Id);

        /// <summary>
        /// 移除表達式
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="expression"></param>
        public static void Remove<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : IAggregateRoot
        => collection.DeleteOne(expression);

        public static IFindFluent<T, T> Where<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression)
        => expression == null ? collection.Find(Builders<T>.Filter.Empty) : collection.Find(expression);

        /// <summary>
        /// MongoDB里面是沒有實現IQueryable的 所以想要使用習慣的SELECT我們只能自己封裝一下
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <typeparam name="TProjection"></typeparam>
        /// <typeparam name="TNewProjection">返回新的數據類型</typeparam>
        /// <param name="IQueryable"></param>
        /// <param name="projection"></param>
        /// <returns></returns>
        public static IFindFluent<TDocument, TNewProjection> Select<TDocument, TProjection, TNewProjection>(this IFindFluent<TDocument, TProjection> IQueryable, Expression<Func<TDocument, TNewProjection>> projection)
        => IQueryable.Project(projection);


        /// <summary>
        /// 獲得篩選后的首個元素
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="IQueryable"></param>
        /// <returns></returns>
        public static T FirstOrDefault<TDocument, T>(this IFindFluent<TDocument, T> IQueryable)
         => IQueryable.First();


        /// <summary>
        /// 直接支持表達式樹后的首個滿足對象
        /// </summary>
        /// <typeparam name="TDocument"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="collection"></param>
        /// <param name="expression"></param>
        /// <returns></returns>
        public static T FirstOrDefault<TDocument, T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression = null)
        => expression == null ? collection.Find(Builders<T>.Filter.Empty).First() : collection.Find(expression).First();
 }

 

Builders<T>.Update.Combine 方法是將多個UpdateDefinition<T>修改設置合並成一個builder對象執行

IFindFluent 所返回的都是MongoDB執行的命令

MongoDB客戶端驅動也是支持異步操作的我這里就沒有寫了 有興趣的可以自己研究下

 

 

5:建立測試倉儲

6:倉儲的實現  是不是看起來有點EF的感覺? ~0~

7:建立Service接口

8 領域服務的實現

9:單元測試用例

 BasicContext Context = new BasicContext();
            Context.Users.Add(new Entity.User()
            {
                Name = "小七子",
                Cardcertificate = "123456789",
                Gender = Entity.Gender.Boy,
                Houses = new System.Collections.Generic.List<Entity.House>() { new Entity.House() { Adress = "中關村110號雙拼別墅" } }
            });

            Context.Users.Where(o => o.Cardcertificate == "110").ToList();

            Context.Users.Update(new Entity.User() { });

            Context.Users.Remove(new Entity.User() { });

            Context.Users.Where().Select(o => o.Name).ToList();
            Console.ReadKey();

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM