仍是一如既往先把結構圖放出來,上上個版本添加了redis的緩存,可是不知足個人需求,由於公司有項目要求是分佈式因此呢,這裏我就增長了mongoDb進行緩存分佈式,好了先看結構圖(1)。git
總的來講比較蛋疼,由於歷來沒有使用過mongoDB,從安裝,到轉爲windows服務,設置權限等等,好吧這都是題外話。redis
在寫這個MongoDB版本的時候遇到的一些問題,我先總結下:sql
1.MongoDb版本是官網最新版3.4.4,官方驅動爲2.4.3,首先個人項目是以GUID作爲主鍵,在往MongonDB中插入時遇到的是將GUID生成了MongoDB的LUUID格式產生了這樣的格式(2)而且和個人數據庫不一樣(3)固然redis也不一樣(4)。shell
a)帶着問題咱們去解決查了文檔發現原來由於bson的鍵要標識成GUID,而且格式要轉爲string,既然知道問題了就去解決找到個人GUID主鍵,以下圖(5):數據庫
在主鍵上加上 [BsonId(IdGenerator = typeof(GuidGenerator)), BsonRepresentation(BsonType.String)]這段就能夠了,看了下效果確實能夠了(6)。windows
2.可是在測試過程當中查詢的時候卻找不到,一查原來個人數據庫redis的id值都不同,這又是怎麼回事?緩存
b)原來mongoDB生成的GUID和C#生成的GUID的進制是不同的,爲了解決這個問題,Google了一下,找到了一個腳本,把這個js腳本放在mongoDB裏面執行一下,而後生成的GUID就和數據庫的同樣了。如圖(7):異步
而後生成的_id就和我數據redis的同樣了。(8)(9)async
解決完成這些問題後開始寫本身的封裝類。分佈式
但願你們多給出建議,博主也是第一次玩mongoDB,若是有好的學習資源也請推薦給博主。
第一步建立鏈接:
using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.MongoDbCache.MongoDbCommon { public class MongoDbManager { private static IMongoDatabase db = null; private static readonly object locker = new object(); /// <summary> /// 使用單列模式建立鏈接 /// </summary> /// <returns></returns> public static IMongoDatabase CreateDb() { if (db == null) { lock (locker) { if (db == null) { MongoClient Client = new MongoClient(MongoDbConfig.Host); db = Client.GetDatabase(MongoDbConfig.DataBase); } } } return db; } } }
第二步建立DB:
using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.MongoDbCache.MongoDbCommon { public class MongoDbBase { private IMongoDatabase db = null; public IMongoDatabase Db { get => db; } public MongoDbBase() { db = MongoDbManager.CreateDb(); } } }
而後呢獻上本身的封裝helper:
using KuRuMi.Mio.DoMain.MongoDbCache.MongoDbCommon; using MongoDB.Bson; using MongoDB.Driver; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.MongoDbCache.MongoDbCache { /// <summary> /// MongoDb緩存 /// </summary> public sealed class MongoDbCacheService : MongoDbBase { #region 同步 #region 增長 /// <summary> /// 保存單個對象 /// </summary> /// <param name="Root"></param> /// <returns></returns> public bool AddSignleObject<TAggregateRoot>(TAggregateRoot Root) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); collection.InsertOne(Root); return true; } catch (Exception) { return false; } } /// <summary> /// 批量保存多個對象 /// </summary> /// <param name="Root"></param> /// <returns></returns> public bool AddManyObject<TAggregateRoot>(List<TAggregateRoot> Root) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); collection.InsertMany(Root); return true; } catch (Exception) { return false; } } #endregion #region 刪除 /// <summary> /// 刪除單個記錄 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="parameter"></param> /// <returns></returns> public int DeleteSingleIndex<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return (int)collection.DeleteOne(filter).DeletedCount; } catch (Exception e) { throw e; } } #endregion #region 查詢 /// <summary> /// 查詢單條記錄 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="parameter"></param> /// <returns></returns> public TAggregateRoot FindSingleIndex<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return collection.Find(filter).FirstOrDefault(); } catch (Exception e) { throw e; } } /// <summary> /// 查詢整個集合 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <returns></returns> public List<TAggregateRoot> FindMany<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return collection.Find(filter).ToList(); } catch (Exception e) { throw e; } } #endregion #region 更新 /// <summary> /// 更新單個值 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <param name="field"></param> /// <param name="parameter"></param> /// <returns></returns> public int UpdateSingle<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter, string name, string parameter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); var set = Builders<TAggregateRoot>.Update.Set(name, parameter); return (int)collection.UpdateOne(filter, set).ModifiedCount; } catch (Exception e) { throw e; } } /// <summary> /// 更新多個值 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <param name="Root"></param> /// <param name="property"></param> /// <param name="replace"></param> public int UpdateMany<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter, TAggregateRoot Root, List<string> property = null, bool replace = false) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); var type = Root.GetType(); //修改集合 var list = new List<UpdateDefinition<TAggregateRoot>>(); foreach (var propert in type.GetProperties()) { if (propert.Name.ToLower() != "id") { try { if (property == null && property.Count < 1 || property.Any(o => o.ToLower() == propert.Name.ToLower())) { var replaceValue = propert.GetValue(Root); if (replaceValue != null) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); else if (replace) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); } } catch (Exception) { if (property == null) { var replaceValue = propert.GetValue(Root); if (replaceValue != null) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); else if (replace) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); } } } } if (list.Count > 0) { var builders = Builders<TAggregateRoot>.Update.Combine(list); return (int)collection.UpdateOne(filter, builders).ModifiedCount; } return 0; } catch (Exception e) { throw e; } } #endregion #endregion #region 異步 #region 增長 /// <summary> /// 異步保存單個對象 /// </summary> /// <param name="Root"></param> /// <returns></returns> public bool AddSignleObjectAsync<TAggregateRoot>(TAggregateRoot Root) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); collection.InsertOneAsync(Root); return true; } catch (Exception) { return false; } } /// <summary> /// 批量保存多個對象 /// </summary> /// <param name="Root"></param> /// <returns></returns> public bool AddManyObjectAsync<TAggregateRoot>(List<TAggregateRoot> Root) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); collection.InsertManyAsync(Root); return true; } catch (Exception) { return false; } } #endregion #region 刪除 /// <summary> /// 異步刪除單個記錄 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="parameter"></param> /// <returns></returns> public int DeleteSingleIndexAsync<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return (int)collection.DeleteOneAsync(filter).Result.DeletedCount; } catch (Exception e) { throw e; } } #endregion #region 查詢 /// <summary> /// 異步查詢單條記錄 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="parameter"></param> /// <returns></returns> public TAggregateRoot FindSingleIndexAsync<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return collection.FindAsync(filter).Result.FirstOrDefault(); } catch (Exception e) { throw e; } } /// <summary> /// 異步查詢整個集合 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <returns></returns> public List<TAggregateRoot> FindManyAsync<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); return collection.FindAsync(filter).Result.ToList(); } catch (Exception e) { throw e; } } #endregion #region 更新 /// <summary> /// 異步更新單個值 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <param name="field"></param> /// <param name="parameter"></param> /// <returns></returns> public int UpdateSingleAsync<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter, string name, string parameter) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); var set = Builders<TAggregateRoot>.Update.Set(name, parameter); return (int)collection.UpdateOneAsync(filter, set).Result.ModifiedCount; } catch (Exception e) { throw e; } } /// <summary> ///異步更新多個值 /// </summary> /// <typeparam name="TAggregateRoot"></typeparam> /// <param name="filter"></param> /// <param name="Root"></param> /// <param name="property"></param> /// <param name="replace"></param> public int UpdateManyAsync<TAggregateRoot>(Expression<Func<TAggregateRoot, bool>> filter, TAggregateRoot Root, List<string> property = null, bool replace = false) { try { var collection = Db.GetCollection<TAggregateRoot>(typeof(TAggregateRoot).Name); var type = Root.GetType(); //修改集合 var list = new List<UpdateDefinition<TAggregateRoot>>(); foreach (var propert in type.GetProperties()) { if (propert.Name.ToLower() != "id") { try { if (property == null && property.Count < 1 || property.Any(o => o.ToLower() == propert.Name.ToLower())) { var replaceValue = propert.GetValue(Root); if (replaceValue != null) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); else if (replace) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); } } catch (Exception) { if (property == null) { var replaceValue = propert.GetValue(Root); if (replaceValue != null) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); else if (replace) list.Add(Builders<TAggregateRoot>.Update.Set(propert.Name, replaceValue)); } } } } if (list.Count > 0) { var builders = Builders<TAggregateRoot>.Update.Combine(list); return (int)collection.UpdateOneAsync(filter, builders).Result.ModifiedCount; } return 0; } catch (Exception e) { throw e; } } #endregion #endregion } }
最後是腳本文件:
function HexToBase64(hex) { var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var base64 = ""; var group; for (var i = 0; i < 30; i += 6) { group = parseInt(hex.substr(i, 6), 16); base64 += base64Digits[(group >> 18) & 0x3f]; base64 += base64Digits[(group >> 12) & 0x3f]; base64 += base64Digits[(group >> 6) & 0x3f]; base64 += base64Digits[group & 0x3f]; } group = parseInt(hex.substr(30, 2), 16); base64 += base64Digits[(group >> 2) & 0x3f]; base64 += base64Digits[(group << 4) & 0x3f]; base64 += "=="; return base64; } function Base64ToHex(base64) { var base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; var hexDigits = "0123456789abcdef"; var hex = ""; for (var i = 0; i < 24;) { var e1 = base64Digits.indexOf(base64[i++]); var e2 = base64Digits.indexOf(base64[i++]); var e3 = base64Digits.indexOf(base64[i++]); var e4 = base64Digits.indexOf(base64[i++]); var c1 = (e1 << 2) | (e2 >> 4); var c2 = ((e2 & 15) << 4) | (e3 >> 2); var c3 = ((e3 & 3) << 6) | e4; hex += hexDigits[c1 >> 4]; hex += hexDigits[c1 & 15]; if (e3 != 64) { hex += hexDigits[c2 >> 4]; hex += hexDigits[c2 & 15]; } if (e4 != 64) { hex += hexDigits[c3 >> 4]; hex += hexDigits[c3 & 15]; } } return hex; } function UUID(uuid) { var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters var base64 = HexToBase64(hex); return new BinData(4, base64); // new subtype 4 } function JUUID(uuid) { var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters var msb = hex.substr(0, 16); var lsb = hex.substr(16, 16); msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2) + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2); lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2) + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2); hex = msb + lsb; var base64 = HexToBase64(hex); return new BinData(3, base64); } function CSUUID(uuid) { var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters var a = hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2); var b = hex.substr(10, 2) + hex.substr(8, 2); var c = hex.substr(14, 2) + hex.substr(12, 2); var d = hex.substr(16, 16); hex = a + b + c + d; var base64 = HexToBase64(hex); return new BinData(3, base64); } function PYUUID(uuid) { var hex = uuid.replace(/[{}-]/g, ""); // remove extra characters var base64 = HexToBase64(hex); return new BinData(3, base64); } BinData.prototype.toUUID = function () { var hex = Base64ToHex(this.base64()); // don't use BinData's hex function because it has bugs in older versions of the shell var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12); return 'UUID("' + uuid + '")'; } BinData.prototype.toJUUID = function () { var hex = Base64ToHex(this.base64()); // don't use BinData's hex function because it has bugs in older versions of the shell var msb = hex.substr(0, 16); var lsb = hex.substr(16, 16); msb = msb.substr(14, 2) + msb.substr(12, 2) + msb.substr(10, 2) + msb.substr(8, 2) + msb.substr(6, 2) + msb.substr(4, 2) + msb.substr(2, 2) + msb.substr(0, 2); lsb = lsb.substr(14, 2) + lsb.substr(12, 2) + lsb.substr(10, 2) + lsb.substr(8, 2) + lsb.substr(6, 2) + lsb.substr(4, 2) + lsb.substr(2, 2) + lsb.substr(0, 2); hex = msb + lsb; var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12); return 'JUUID("' + uuid + '")'; } BinData.prototype.toCSUUID = function () { var hex = Base64ToHex(this.base64()); // don't use BinData's hex function because it has bugs in older versions of the shell var a = hex.substr(6, 2) + hex.substr(4, 2) + hex.substr(2, 2) + hex.substr(0, 2); var b = hex.substr(10, 2) + hex.substr(8, 2); var c = hex.substr(14, 2) + hex.substr(12, 2); var d = hex.substr(16, 16); hex = a + b + c + d; var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12); return 'CSUUID("' + uuid + '")'; } BinData.prototype.toPYUUID = function () { var hex = Base64ToHex(this.base64()); // don't use BinData's hex function because it has bugs var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12); return 'PYUUID("' + uuid + '")'; } BinData.prototype.toHexUUID = function () { var hex = Base64ToHex(this.base64()); // don't use BinData's hex function because it has bugs var uuid = hex.substr(0, 8) + '-' + hex.substr(8, 4) + '-' + hex.substr(12, 4) + '-' + hex.substr(16, 4) + '-' + hex.substr(20, 12); return 'HexData(' + this.subtype() + ', "' + uuid + '")'; }
倉儲層的調用:
using KuRuMi.Mio.DoMain.Model.Model; using KuRuMi.Mio.DoMain.Model.Repositories; using KuRuMi.Mio.DoMain.Repository.EFRepository; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace KuRuMi.Mio.DoMain.Repository.ModelRepository { public class UserRepositoryImpl : RepositoryImpl<User>, IUserRepository { public KurumiMioDbContext context => lazy.Context as KurumiMioDbContext; /// <summary> /// 登陸 /// </summary> /// <param name="Email"></param> /// <param name="PassWord"></param> /// <returns></returns> public string CheckUser(string Email, string PassWord) { try { User entity = null; //MongoDb取 entity = Mongo.FindSingleIndex<User>(a => a.Email == Email); if (entity == null) { //redis取 entity = Redis.RedisString.Value.StringGet<User>(Email); } if (entity == null) { //數據庫取 string sql = "select Id,UserName,Password,email from [User] as a where a.Email ='{0}' and a.PassWord ='{1}'"; string select = string.Format(sql, Email, PassWord); entity = context.user.SqlQuery(select).FirstOrDefault(); } return entity.UserName; } catch (Exception e) { return ""; } } /// <summary> /// 保存 /// </summary> /// <param name="aggregateRoot"></param> public async override void Add(User aggregateRoot) { base.Add(aggregateRoot); await Redis.RedisString.Value.StringSetAsync(aggregateRoot.Email, aggregateRoot);//保存一份到redis Mongo.AddSignleObjectAsync(aggregateRoot);//保存一份到mongoDb } /// <summary> /// 註冊 /// </summary> /// <param name="info"></param> /// <returns></returns> public User GetAll(User info) { string sql = "select Id,UserName,Password,email from [User] as a where a.UserName ='{0}' and email ='{1}'"; string select = string.Format(sql, info.UserName, info.Email); return context.user.SqlQuery(select).FirstOrDefault(); } } }
圖1:
圖2:
圖3:
圖4:
圖5:
圖6:
圖7:
圖8:
圖9: