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:123456@127.0.0.1:27017",
    "DefaultDataBase": "mydb"
  },

网上查到一句话

 最终把db名字加到了后面

// mongoDb配置
  "MongoOption": {
    "MongoHost": "mongodb://me:123456@127.0.0.1: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方法不需要加)。



原文地址:https://www.cnblogs.com/xiaojidanbai/p/14197557.html