spring boot 遷移至asp.net core
asp.net core類似於spring boot,內建了一個kerstral web伺服器,所以可以直接通過dotnet啟動,然後訪問。
本文著重於.net操作mongodb的過程
框架新增mongoHelper
因為EFcore是不支援mongoHelper,所以只能通過MongoClient來訪問資料庫
首先框架中新增mongoHelper類,mongoHelper通過泛型來實現增刪改查,資料庫配置在appSetting.json中,然後把mongoHelper注入容器
public static class MongoServiceCollectionExtension {public static void AddMongoDb(this IServiceCollection services, IConfiguration configuration) { services.Configure<MongoOption>(configuration.GetSection("MongoOption")); services.AddSingleton<MongoClientHelper>(); services.AddSingleton<MongoHelper>(); } }
public class MongoHelper { private IMongoDatabase _dataBase; private MongoClient _client; public MongoHelper(MongoClientHelper clienthelper, IOptions<MongoOption> option) { _client = clienthelper.GetMongoClient(); _dataBase = _client.GetDatabase(option.Value.DefaultDataBase); }public void SwitchDataBase(string dataBaseName) { _dataBase = _client.GetDatabase(dataBaseName); } private IMongoCollection<T> GetCollection<T>() { return _dataBase.GetCollection<T>(typeof(T).Name); } private IMongoCollection<BsonDocument> GetAggregrationCollection<T>() { return _dataBase.GetCollection<BsonDocument>(typeof(T).Name); } }
下面來詳細說說遇到的坑
1. 獲取不到配置的database
一開始的配置如下,然後發現最後獲取的database是預設的admin,並不是配置的mydb
// mongoDb配置 "MongoOption": { "MongoHost": "mongodb://me:[email protected]:27017", "DefaultDataBase": "mydb" },
網上查到一句話
最終把db名字加到了後面
// mongoDb配置 "MongoOption": { "MongoHost": "mongodb://me:[email protected]:27017/mydb", },
2. 讀取表資料報錯,不能將string轉換成DateTime
由於mongo的特性,不管我插入什麼資料都行,只要把對應的model改成你想要的就行。但是讀取的時候我們必須指定一個model,那麼假如這個model以前插入過資料,然後被修改了又插入過資料,當你讀取的時候就會報錯。我這邊有個欄位原來是string型別的,用了一段時間後,被改成了DateTime型別。當我使用mongo的find方法時,他就報錯了string不能轉換成datetime。
然後我嘗試著增加建構函式,或者修改setter方法,但是依然沒有用
於是我在mongo裡面增加了一個方法,可以看到上圖中有2個GetCollection方法,第二個是給聚合函式用的,
/// <summary> /// 根據條件查詢資料 /// </summary> public List<T> Get<T>(FilterDefinition<T> filter) { return GetCollection<T>().Find(filter).ToList(); } /// <summary> /// 聚合查詢表T /// </summary> /// <typeparam name="T"></typeparam> /// <param name="pipeline"></param> /// <returns></returns> public async Task<List<BsonDocument>> AggregateAsync<T>(PipelineDefinition<BsonDocument, BsonDocument> pipeline) { return (await GetAggregrationCollection<T>().AggregateAsync(pipeline)).ToList(); }
第二個查找出來的是BsonDocument型別的list,需要轉換成對應的model list
protected List<TaskCats> ConvertAggregateResultToTaskCats(List<BsonDocument> queryResults) { if (!queryResults.Any()) return null; return queryResults.Select(result => { // 歷史遺留問題,reportingTime可能為空,為string,為datetime //var reportingTime = result["reportingTime"]; var reportingTime = result.GetValue("reportingTime"); return new TaskCats( result["adAccount"].ToString(), Convert.ToDateTime(result["reportedDate"]), reportingTime.ToString() == "BsonNull" ? Convert.ToDateTime("1990-11-11") : Convert.ToDateTime(reportingTime), Convert.ToDateTime(result["startDate"]), result["taskId"].ToString(), result.GetValue("description", null)?.ToString(), result.GetValue("weekday", null)?.ToString(), Convert.ToDouble(result["workingHours"]), result.GetValue("BUName", null)?.ToString(), result.GetValue("priority", null)?.ToString(), result.GetValue("projectName", null)?.ToString(), result.GetValue("otherProject", null)?.ToString(), result["_id"].ToString()); }).ToList(); }
框架到此為止(最後那個轉換是在業務層實現,因為會涉及到具體的entity)
業務類實現
controller實現互動,service負責具體的操作,聯動model和entity以及dao層的mongoHelper。
這裡有一個前期資料匯入的類,比如說匯入初始管理員以及menu列表,這一塊是跟業務相關的,我把它放在了業務層。
編寫IHost的extension類,通過IServiceScope獲取注入的類物件,實現資料庫插入
/// <summary> /// Initialize the mongodb data, insert menu info and admin user. /// </summary> /// <param name="host">The host</param> public static void InitialData(this IHost host) { using var serviceScope = host.Services.CreateScope(); var mongoHelper = serviceScope.ServiceProvider.GetRequiredService<MongoHelper>(); AddMenuInfo(mongoHelper); if (!IsDefaultUserExsit(mongoHelper)) { AddDefaultUser(mongoHelper); } }
配置validation
使用FluentValidation:https://www.cnblogs.com/lwqlun/p/10311945.html
返回badRequest跟controller格式一致
這個Extension是屬於框架類,這邊只是展示用
一些問題
1. 因為spring boot預設會給表增加_class欄位用於對映,但是.net使用mongoClient並不需要這個欄位,假如不定義就會報錯。暫時沒有找到很好的解決辦法,定義了一個_class屬性。
2. 對於Nlog,路徑一定要用/,不能用\. 因為linux下會找不到路徑,導致所有的log都記錄在根目錄下面
3. MongoDb時區問題
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
很多攻略說新增這個特性,其實這個特性的意思是跟jvm設定一樣的,插入的時候,mongo驅動會自動把時間轉換成0時區的時間,存入資料庫,然後你會發現資料庫中的資料跟實際的比對確實是少了8個小時。查詢的時候,查出來的資料,mongo驅動會自動再加上8小時,所以你使用的時候就感覺不出有問題。假如你需要資料庫裡面儲存的時間跟實際的一致,那麼不管你插入還是查詢都必須加8小時(對於mongo的insert和find是這樣,但是aggregate方法不需要加)。