当前位置: 首页 > news >正文

江苏网站优化建站/专业搜索引擎seo服务

江苏网站优化建站,专业搜索引擎seo服务,宝塔面板建设网站,门头沟富阳网站建设WebAppDbTest 项目准备 项目准备1、.net cli 创建项目2、nuget 包引用和项目结构2.1、项目添加相关 nuget 包2.2、WebAppDbTest 项目结构 3、项目代码说明3.1、CSharp/C# 类文件说明3.2、json 配置文件说明 4、项目运行预览 数据库 .db 文件准备1、创建 SQLite 数据库1.1、在 W…

WebAppDbTest 项目准备

  • 项目准备
    • 1、.net cli 创建项目
    • 2、nuget 包引用和项目结构
      • 2.1、项目添加相关 nuget 包
      • 2.2、WebAppDbTest 项目结构
    • 3、项目代码说明
      • 3.1、CSharp/C# 类文件说明
      • 3.2、json 配置文件说明
    • 4、项目运行预览
  • 数据库 .db 文件准备
    • 1、创建 SQLite 数据库
      • 1.1、在 Windows 上安装 SQLite
      • 1.2、创建 SQLite 数据库
    • 2、创建 LiteDB 数据库
      • 2.1、LiteDB.Shell
      • 2.2、创建 LiteDB 数据库

项目准备

此处还是以默认的 WeatherForecast(天气预报) 的数据为例,分别对两种类型的数据库做相应的 crud 操作,并对比测试性能。

1、.net cli 创建项目

这里我们使用的 .net8 版本,.net cli 创建 WebAppDbTest 项目,执行命令如下:

dotnet new webapi -o WebAppDbTest --no-https -f net8.0

2、nuget 包引用和项目结构

2.1、项目添加相关 nuget 包

  <ItemGroup><PackageReference Include="FreeSql" Version="3.2.805" /><PackageReference Include="FreeSql.Provider.Sqlite" Version="3.2.805" /><PackageReference Include="FreeSql.Repository" Version="3.2.805" /><PackageReference Include="LiteDB.Async" Version="0.1.7" /><PackageReference Include="Mapster.Async" Version="2.0.1" /><PackageReference Include="Serilog.AspNetCore" Version="8.0.0" /><PackageReference Include="Serilog.Sinks.LiteDB" Version="1.0.29" /><PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /></ItemGroup>

2.2、WebAppDbTest 项目结构

左边部分为 Nuget 安装的依赖包,右边部分为项目整体目录结构。

WebAppDbTest

3、项目代码说明

3.1、CSharp/C# 类文件说明

1、控制器类(Controllers

  • LiteDbController.cs,针对 LiteDb 数据库的 CRUD 方法;
  • SqliteController.cs,针对 SQLite 数据库的 CRUD 方法;
  • WeatherForecastController.cs(项目默认的类);

2、模型类(Models

  • ActionExecTime.cs,记录方法执行时间;
  • AppLogs.cs,记录日志信息;
  • WeatherForecast.cs,天气预报数据模型;

3、服务类(Services

  • AppLogsServices.cs,提供日志写入相关方法;
using System.Text.Json;
using WebAppDbTest.Models;namespace WebAppDbTest.Services;/// <summary>
/// 接口规范定义
/// </summary>
public interface IAppLogsServices
{/// <summary>/// 写入日志信息/// </summary>/// <param name="logs"></param>/// <param name="logLevel"></param>/// <returns></returns>Task WriteLogAsync(AppLogs logs, LogLevel logLevel = LogLevel.Information);/// <summary>/// 模型数据序列化json字符串/// </summary>/// <typeparam name="TData"></typeparam>/// <param name="data"></param>/// <returns></returns>Task<string> JsonSerializeAsync<TData>(TData data);
}/// <summary>
/// 接口规范实现
/// </summary>
public class AppLogsServices : IAppLogsServices
{#region 构造函数 DIprivate readonly ILogger<AppLogsServices> _logger;public AppLogsServices(ILogger<AppLogsServices> logger){_logger = logger;}#endregion/// <summary>/// 写入日志信息/// </summary>/// <param name="logs"></param>/// <param name="logLevel"></param>/// <returns></returns>public async Task WriteLogAsync(AppLogs logs, LogLevel logLevel = LogLevel.Information){logs.LogLevel = logLevel;string jsonLogs = await JsonSerializeAsync(logs);switch (logLevel){case LogLevel.Trace:_logger.LogTrace(jsonLogs);break;case LogLevel.Debug:_logger.LogDebug(jsonLogs);break;case LogLevel.Information:_logger.LogInformation(jsonLogs);break;case LogLevel.Warning:_logger.LogWarning(jsonLogs);break;case LogLevel.Error:_logger.LogError(jsonLogs);break;case LogLevel.Critical:_logger.LogCritical(jsonLogs);break;case LogLevel.None:_logger.LogInformation(jsonLogs);break;default:_logger.LogInformation(jsonLogs);break;}}/// <summary>/// json 序列化/// </summary>/// <typeparam name="TData"></typeparam>/// <param name="data"></param>/// <returns></returns>public async Task<string> JsonSerializeAsync<TData>(TData data){var options = new JsonSerializerOptions{PropertyNameCaseInsensitive = true};await using var stream = new MemoryStream();await JsonSerializer.SerializeAsync(stream, data, options);stream.Position = 0;using var reader = new StreamReader(stream);return await reader.ReadToEndAsync();}
}
  • WeatherForecastServices.cs,模拟天气预报的数据;
using LiteDB;
using LiteDB.Async;
using Mapster;
using System.Diagnostics;
using System.Linq.Expressions;
using WebAppDbTest.Models;namespace WebAppDbTest.Services;/// <summary>
/// 天气预报接口规范定义
/// </summary>
public interface IWeatherForecastServices
{/// <summary>/// 获取天气预报概要/// </summary>/// <returns></returns>string GetSummarie();/// <summary>/// 获取天气预报列表/// </summary>/// <param name="count"></param>/// <returns></returns>IEnumerable<WeatherForecast> GetWeatherForecasts(int count);#region about litedb crudTask<Guid> LiteDbAddSingleAsync<T>(string collectioName, T t);Task<int> LiteDbAddBulkAsync<T>(string collectioName, IEnumerable<T> list);Task<T> LiteDbGetSingleAsync<T>(string collectioName, Guid id);Task<IEnumerable<T>> LiteDbGetAllAsync<T>(string collectioName);Task<bool> LiteDbUpdateSingleAsync<T>(string collectioName, T t);Task<int> LiteDbUpdateBulkAsync<T>(string collectioName, IEnumerable<T> list);Task<bool> LiteDbDeleteSingleAsync<T>(string collectioName, Guid id);Task<int> LiteDbDeleteBulkAsync<T>(string collectioName, Expression<Func<T, bool>> predicate);#endregion#region about sqlite crudTask<Guid> SqliteAddSingleAsync<T>(T t) where T : BaseEntity;Task<int> SqliteAddBulkAsync<T>(IEnumerable<T> list) where T : BaseEntity;Task<T> SqliteGetSingleAsync<T>(Guid id) where T : BaseEntity;Task<IEnumerable<T>> SqliteGetAllAsync<T>() where T : BaseEntity;Task<bool> SqliteUpdateSingleAsync<T>(T t) where T : BaseEntity, new();Task<int> SqliteUpdateBulkAsync<T>(IEnumerable<T> list) where T : BaseEntity, new();Task<bool> SqliteDeleteSingleAsync<T>(Guid id) where T : BaseEntity;Task<int> SqliteDeleteBulkAsync<T>(List<Guid> ids) where T : BaseEntity;#endregion
}/// <summary>
/// 天气预报接口规范实现,模拟天气预报的数据
/// </summary>
public class WeatherForecastServices : IWeatherForecastServices
{#region 构造函数 DIprivate readonly IAppLogsServices _logger;private readonly IConfiguration _configuration;private readonly IFreeSql _freeSql;private readonly IWebHostEnvironment _webHostEnvironment;public WeatherForecastServices(IAppLogsServices logger,IConfiguration configuration,IFreeSql freeSql,IWebHostEnvironment webHostEnvironment){_logger = logger;_configuration = configuration;_freeSql = freeSql;_webHostEnvironment = webHostEnvironment;}#endregion#region 模拟数据/// <summary>/// 模拟天气情况摘要数据列表/// </summary>private static readonly string[] Summaries = new[]{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};public string GetSummarie() => Summaries[Random.Shared.Next(Summaries.Length)];public IEnumerable<WeatherForecast> GetWeatherForecasts(int count){if (count <= 0 || count > 1000) count = 1000;/** 等效代码如下return Enumerable.Range(1, count).Select(index => {int temperatureC = Random.Shared.Next(-20, 55);var wf = new WeatherForecast{Id = Guid.NewGuid(),//Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),Date = DateTime.Now.AddDays(index),TemperatureC = temperatureC,TemperatureF = 32 + (int)(temperatureC / 0.5556),Summary = GetSummarie()};return wf;}).ToArray();*/return Enumerable.Range(1, count).Select(index => GetWeatherForecast(index)).ToArray();}private WeatherForecast GetWeatherForecast(int index) {int temperatureC = Random.Shared.Next(-20, 55);var wf = new WeatherForecast{Id = Guid.NewGuid(),Date = DateTime.Now.AddDays(index),TemperatureC = temperatureC,TemperatureF = 32 + (int)(temperatureC / 0.5556),Summary = GetSummarie()};return wf;}#endregionprivate enum DbFileType { LiteDB, SQLite };private string GetConnString(int index, DbFileType dbFileType = DbFileType.LiteDB) {string? dbFile = _configuration.GetSection($"DbConfig:{index}:DbFilePath").Value;string filePath = Path.Combine(_webHostEnvironment.ContentRootPath, dbFile);string dbConnString = string.Empty;switch (dbFileType){case DbFileType.LiteDB:dbConnString = $"Filename={ filePath };Connection=shared;Password=123456";break;case DbFileType.SQLite:dbConnString = $"Data Source={ filePath };Version=3;Pooling=False;Max Pool Size=100";break;default:dbConnString = $"Filename={ filePath };Connection=shared;Password=123456";break;}return dbConnString;}private static readonly Stopwatch _sw = new();/// <summary>/// 记录信息/// </summary>/// <param name="ts">方法执行耗时,单位:毫秒/ms</param>/// <param name="appLogs"></param>/// <returns></returns>private async Task LiteDbWraiteInfoAsync(ActionExecInfo actionExecInfo, AppLogs appLogs){// 记录操作方法执行的时间string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<ActionExecInfo>(nameof(ActionExecInfo));var item = await collection.InsertAsync(actionExecInfo);appLogs.ActionExecInfoId = item.AsGuid;// 记录日志await _logger.WriteLogAsync(appLogs);}#region About LiteDb CRUDpublic async Task<Guid> LiteDbAddSingleAsync<T>(string collectioName, T t){_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);var item = await collection.InsertAsync(t);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "AddSingle",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "AddSingle",ItemCount = 1,OperationInfo = $"[AddSingle] ==> 插入数据:1条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return item.AsGuid;}public async Task<int> LiteDbAddBulkAsync<T>(string collectioName, IEnumerable<T> list){_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个表和 MongoDB 一样的var collection = db.GetCollection<T>(collectioName);int rcount = await collection.InsertBulkAsync(list);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "AddBulk",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "AddBulk",ItemCount = 1,OperationInfo = $"[AddBulk] ==> 插入数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}public async Task<T> LiteDbGetSingleAsync<T>(string collectioName, Guid id) {_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);var result = await collection.FindByIdAsync(id); // 下面代码等效// var item = await collection.FindOneAsync(x => x.Id == id);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "GetSingle",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "GetSingle",ItemCount = 1,OperationInfo = $"[GetSingle] ==> 查询数据:1条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return result;}public async Task<IEnumerable<T>> LiteDbGetAllAsync<T>(string collectioName){_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);var result = await collection.FindAllAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "GetAll",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "GetAll",ItemCount = result.Count(),OperationInfo = $"[GetAll] ==> 查询数据:{result.Count()}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return result;}public async Task<bool> LiteDbUpdateSingleAsync<T>(string collectioName, T t) {_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);bool isOk = await collection.UpdateAsync(t);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "UpdateSingle",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "UpdateSingle",ItemCount = 1,OperationInfo = $"[UpdateSingle] ==> 更新数据:1条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return isOk;}public async Task<int> LiteDbUpdateBulkAsync<T>(string collectioName, IEnumerable<T> list){_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);int rcount = await collection.UpdateAsync(list);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "UpdateBulk",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "UpdateBulk",ItemCount = rcount,OperationInfo = $"[UpdateBulk] ==> 更新数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}public async Task<bool> LiteDbDeleteSingleAsync<T>(string collectioName, Guid id) {_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);bool isOk = await collection.DeleteAsync(id);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "DeleteSingle",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "DeleteSingle",ItemCount = 1,OperationInfo = $"[DeleteSingle] ==> 删除数据:1条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return isOk;}public static BsonValue Serialize(Guid id) => new BsonDocument(new Dictionary<string, BsonValue>{{"_id", id }});public static Guid Deserialize(BsonValue bsonValue){var id = bsonValue["_id"].AsGuid;return id;}public async Task<int> LiteDbDeleteBulkAsync<T>(string collectioName, Expression<Func<T, bool>> predicate) {_sw.Start();string connectionString = GetConnString(0);//打开数据库,如果不存在会自动创建。using var db = new LiteDatabaseAsync(connectionString);//打开一个集合和 MongoDB 一样的,类似关系数据库的表。var collection = db.GetCollection<T>(collectioName);//int rcount = await collection.DeleteAllAsync();int rcount = await collection.DeleteManyAsync(predicate);_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "DeleteBulk",ExecTime = ts,Database = "litedb"};// 记录日志var appLogs = new AppLogs{Label = "DeleteBulk",ItemCount = rcount,OperationInfo = $"[DeleteBulk] ==> 删除数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}#endregion#region About SQLite CRUDpublic async Task<Guid> SqliteAddSingleAsync<T>(T t) where T : BaseEntity{_sw.Start();var rcount = await _freeSql.Insert(t).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "AddSingle",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "AddSingle",ItemCount = rcount,OperationInfo = $"[AddSingle] ==> 插入数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return t.Id;}public async Task<int> SqliteAddBulkAsync<T>(IEnumerable<T> list) where T : BaseEntity{_sw.Start();int rcount = await _freeSql.Insert(list).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "AddBulk",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "AddBulk",ItemCount = 1,OperationInfo = $"[AddBulk] ==> 插入数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}public async Task<T> SqliteGetSingleAsync<T>(Guid id) where T : BaseEntity{_sw.Start();var result = await _freeSql.Select<T>().Where(x => x.Id == id).FirstAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "GetSingle",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "GetSingle",ItemCount = 1,OperationInfo = $"[GetSingle] ==> 查询数据:1条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return result;}public async Task<IEnumerable<T>> SqliteGetAllAsync<T>() where T : BaseEntity{_sw.Start();var result = await _freeSql.Select<T>().ToListAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "GetAll",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "GetAll",ItemCount = result.Count(),OperationInfo = $"[GetAll] ==> 查询数据:{result.Count()}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return result;}public async Task<bool> SqliteUpdateSingleAsync<T>(T t) where T : BaseEntity, new(){_sw.Start();// 推荐快照模式var repo = _freeSql.GetRepository<T>();var item = new T { Id = t.Id };repo.Attach(item); //此时快照 itemt.Adapt(item);//bool isOk = ReferenceEquals(item, t);int rcount = await repo.UpdateAsync(item); //对比快照时的变化// 传统模式// int rcount = await _freeSql.Update<T>().SetSource(t).IgnoreColumns(a => new { a.Id }).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "UpdateSingle",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "UpdateSingle",ItemCount = rcount,OperationInfo = $"[UpdateSingle] ==> 更新数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount > 0;}public async Task<int> SqliteUpdateBulkAsync<T>(IEnumerable<T> list) where T : BaseEntity, new(){_sw.Start();// 推荐快照模式var repo = _freeSql.GetRepository<T>();var items = list.Select(x => new T{ Id = x.Id });repo.Attach(items); //此时快照 item//list.Adapt(items);items = list;bool isOk = ReferenceEquals(items, list);int rcount = await repo.UpdateAsync(items); //对比快照时的变化// 传统模式//int rcount = await _freeSql.Update<T>().SetSource(list).IgnoreColumns(a => new { a.Id }).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "UpdateBulk",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "UpdateBulk",ItemCount = rcount,OperationInfo = $"[UpdateBulk] ==> 更新数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}public async Task<bool> SqliteDeleteSingleAsync<T>(Guid id) where T : BaseEntity{_sw.Start();int rcount = await _freeSql.Delete<T>().Where(x => x.Id == id).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "DeleteSingle",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "DeleteSingle",ItemCount = rcount,OperationInfo = $"[DeleteSingle] ==> 删除数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount > 0;}public async Task<int> SqliteDeleteBulkAsync<T>(List<Guid> ids) where T : BaseEntity{_sw.Start();int rcount = await _freeSql.Delete<T>(ids.ToArray()).ExecuteAffrowsAsync();_sw.Stop();TimeSpan ts = _sw.Elapsed;// 记录操作方法执行的时间var actionExecInfo = new ActionExecInfo{ActionName = "DeleteBulk",ExecTime = ts,Database = "sqlite"};// 记录日志var appLogs = new AppLogs{Label = "DeleteBulk",ItemCount = rcount,OperationInfo = $"[DeleteBulk] ==> 删除数据:{rcount}条,耗时:{ts.TotalMilliseconds}ms."};await LiteDbWraiteInfoAsync(actionExecInfo, appLogs);return rcount;}#endregion
}

4、程序入口类

  • Program.cs
using Serilog;
using WebAppDbTest.Services;var builder = WebApplication.CreateBuilder(args);//const string OUTPUT_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}";
const string OUTPUT_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level:u3}] {Message:lj}{NewLine}{Exception}";
char b = Path.DirectorySeparatorChar; // 符号 // creates custom collection `applog`
Log.Logger = new LoggerConfiguration().MinimumLevel.Information().Enrich.FromLogContext().CreateLogger();#region Host
builder.Host.ConfigureAppConfiguration((context, config) => {string configPath = $"{context.HostingEnvironment.ContentRootPath}{b}AppData{b}Configuration";config.SetBasePath(configPath).AddJsonFile("appsettings.json", optional: false, reloadOnChange: true).AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true).AddEnvironmentVariables();
}).UseSerilog((context, logger) => {string liteDbPath = Path.Combine(context.HostingEnvironment.ContentRootPath, $"AppData{b}DataBase{b}LiteDbLogs.db");logger.WriteTo.LiteDB(liteDbPath, logCollectionName: "applog");logger.WriteTo.Console(outputTemplate: OUTPUT_TEMPLATE);
});
// .UseSerilog(Log.Logger, dispose: true);
#endregion#region Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();// 注册 AppLogsServices
builder.Services.AddScoped<IAppLogsServices, AppLogsServices>();
// 注册 WeatherForecastServices
builder.Services.AddScoped<IWeatherForecastServices, WeatherForecastServices>();// 注入 Sqlite 类型的 IFreeSql 
//string sqlitePath = $"AppData{b}DataBase{b}SQLiteTest.db";
string sqlitePath = builder.Configuration.GetSection("DbConfig:1:DbFilePath").Value;
string connStr = $"Data Source={Path.Combine(builder.Environment.ContentRootPath, sqlitePath)};Version=3;Pooling=False;Max Pool Size=100";
// Log.Logger.Information(connStr);IFreeSql fsql = new FreeSql.FreeSqlBuilder().UseConnectionString(dataType: FreeSql.DataType.Sqlite, connectionString: connStr).UseAutoSyncStructure(false) //自动同步实体结构【开发环境必备】,FreeSql不会扫描程序集,只有CRUD时才会生成表。//.UseMonitorCommand(cmd => Console.Write(cmd.CommandText)) .UseMonitorCommand(cmd => Log.Logger.Information(cmd.CommandText)).Build(); //请务必定义成 Singleton 单例模式
builder.Services.AddSingleton(fsql); 
#endregionvar app = builder.Build();#region Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}app.UseAuthorization();
app.MapControllers(); 
#endregionapp.Run();

3.2、json 配置文件说明

  • appsettings.json
{"Logging": {"LogLevel": {"Default": "Information","Microsoft.AspNetCore": "Warning","Microsoft.Hosting.Lifetime": "Information"}},"AllowedHosts": "*","DbConfig": [{"DbType": "LiteDB","DbFilePath": "AppData\\DataBase\\LiteDbTest.db"},{"DbType": "SQLite","DbFilePath": "AppData\\DataBase\\SqliteTest.db"}]
}

相关文件代码此处就不再详细说明,感兴趣的可自行查看项目地址:

  • WebAppDbTesthttps://gitee.com/dolayout/sample/tree/master/code/Sample.WebAppDbTest

4、项目运行预览

  • 启动 WebAppDbTestswagger 页面显示如下:

webapp

  • LiteDB & Sqlite 对应的 CRUD 方法:

webapp-dbtest-crud

数据库 .db 文件准备

1、创建 SQLite 数据库

请访问 SQLite 下载页面,从 Windows 区下载预编译的二进制文件。

1.1、在 Windows 上安装 SQLite

  • SQLite 下载,https://www.sqlite.org/download.html
    sqlite-download

此处我是 Windows 11 x64 环境,下载文件分别如下:

  • sqlite-dll-win-x64-3440200.zip
  • sqlite-tools-win-x64-3440200.zip

把下载文件拷贝到 D 盘并解压文件,如下所示:

sqlite

文件夹默认文件说明:

  • sqlite-dll-win-x64-3440200 文件夹默认包含:sqlite3.defsqlite3.dll 文件;
  • sqlite-tools-win-x64-3440200 文件夹默认包含:sqldiff.exesqlite3.exesqlite3_analyzer.exe 文件;

可以把 D:\sqlite\sqlite-tools-win-x64-3440200 添加到 PATH 环境变量,最后在命令提示符下,使用 sqlite3 命令,此处我就不添加环境变量了,直接双击 sqlite.exe 文件将显示如下结果:

sqlite-tools-win-x64

1.2、创建 SQLite 数据库

依据终端提示信息,输入命令创建数据库 SQLiteTest.db 文件,执行如下:

sqlite> .open SQLiteTest.db

查看 sqlite 更多命令帮助信息:

SQLite version 3.44.2 2023-11-24 11:41:44 (UTF-16 console I/O)
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open SQLiteTest.db
sqlite> PRAGMA key = '123456';
sqlite> .help
.archive ...             Manage SQL archives
.auth ON|OFF             Show authorizer callbacks
.backup ?DB? FILE        Backup DB (default "main") to FILE
.bail on|off             Stop after hitting an error.  Default OFF
.cd DIRECTORY            Change the working directory to DIRECTORY
.changes on|off          Show number of rows changed by SQL
.check GLOB              Fail if output since .testcase does not match
.clone NEWDB             Clone data into NEWDB from the existing database
.connection [close] [#]  Open or close an auxiliary database connection
.crnl on|off             Translate \n to \r\n.  Default ON
.databases               List names and files of attached databases
.dbconfig ?op? ?val?     List or change sqlite3_db_config() options
.dbinfo ?DB?             Show status information about the database
.dump ?OBJECTS?          Render database content as SQL
.echo on|off             Turn command echo on or off
.eqp on|off|full|...     Enable or disable automatic EXPLAIN QUERY PLAN
.excel                   Display the output of next command in spreadsheet
.exit ?CODE?             Exit this program with return-code CODE
.expert                  EXPERIMENTAL. Suggest indexes for queries
.explain ?on|off|auto?   Change the EXPLAIN formatting mode.  Default: auto
.filectrl CMD ...        Run various sqlite3_file_control() operations
.fullschema ?--indent?   Show schema and the content of sqlite_stat tables
.headers on|off          Turn display of headers on or off
.help ?-all? ?PATTERN?   Show help text for PATTERN
.import FILE TABLE       Import data from FILE into TABLE
.indexes ?TABLE?         Show names of indexes
.limit ?LIMIT? ?VAL?     Display or change the value of an SQLITE_LIMIT
.lint OPTIONS            Report potential schema issues.
.load FILE ?ENTRY?       Load an extension library
.log FILE|on|off         Turn logging on or off.  FILE can be stderr/stdout
.mode MODE ?OPTIONS?     Set output mode
.nonce STRING            Suspend safe mode for one command if nonce matches
.nullvalue STRING        Use STRING in place of NULL values
.once ?OPTIONS? ?FILE?   Output for the next SQL command only to FILE
.open ?OPTIONS? ?FILE?   Close existing database and reopen FILE
.output ?FILE?           Send output to FILE or stdout if FILE is omitted
.parameter CMD ...       Manage SQL parameter bindings
.print STRING...         Print literal STRING
.progress N              Invoke progress handler after every N opcodes
.prompt MAIN CONTINUE    Replace the standard prompts
.quit                    Stop interpreting input stream, exit if primary.
.read FILE               Read input from FILE or command output
.recover                 Recover as much data as possible from corrupt db.
.restore ?DB? FILE       Restore content of DB (default "main") from FILE
.save ?OPTIONS? FILE     Write database to FILE (an alias for .backup ...)
.scanstats on|off|est    Turn sqlite3_stmt_scanstatus() metrics on or off
.schema ?PATTERN?        Show the CREATE statements matching PATTERN
.separator COL ?ROW?     Change the column and row separators
.session ?NAME? CMD ...  Create or control sessions
.sha3sum ...             Compute a SHA3 hash of database content
.shell CMD ARGS...       Run CMD ARGS... in a system shell
.show                    Show the current values for various settings
.stats ?ARG?             Show stats or turn stats on or off
.system CMD ARGS...      Run CMD ARGS... in a system shell
.tables ?TABLE?          List names of tables matching LIKE pattern TABLE
.timeout MS              Try opening locked tables for MS milliseconds
.timer on|off            Turn SQL timer on or off
.trace ?OPTIONS?         Output each SQL statement as it is run
.version                 Show source, library and compiler versions
.vfsinfo ?AUX?           Information about the top-level VFS
.vfslist                 List all available VFSes
.vfsname ?AUX?           Print the name of the VFS stack
.width NUM1 NUM2 ...     Set minimum column widths for columnar output
sqlite>

此时在当前目录下,SQLite 的数据库文件 SQLiteTest.db 文件就创建好了。

接下来使用 dbeaver-ce 工具连接数据库文件测试:

连接测试

  • sqlite 数据表脚本:
-- WeatherForecast definitionCREATE TABLE "WeatherForecast" (  "Id" CHARACTER(36) NOT NULL, "Date" TEXT NOT NULL, "TemperatureC" INTEGER NOT NULL, "TemperatureF" INTEGER NOT NULL, "Summary" NVARCHAR(255), PRIMARY KEY ("Id")
);

2、创建 LiteDB 数据库

2.1、LiteDB.Shell

LiteDB 项目包含一个简单的控制台应用程序 (LiteDB.Shell.exe),可用于查看、更新以及测试你的数据,在处理你的数据库时非常有用。

  • LiteDB.Shell 项目地址,https://github.com/mustakimali/LiteDB.Shell.NetCore

2.2、创建 LiteDB 数据库

使用 LiteDB.Shell 创建数据库,执行如下命令:

> open <filename>|<connectionString>Open/Crete a new database

基本 Shell 命令,尝试使用 help full 执行所有命令:

Basic Shell Commands - try `help full` for all commands
=======================================================
> open <filename>|<connectionString>Open/Crete a new database> show collectionsList all collections inside database> db.<collection>.insert <jsonDoc>Insert a new document into collection> db.<collection>.update <jsonDoc>Update a document inside collection> db.<collection>.delete <filter>Delete documents using a filter clausule (see find)> db.<collection>.find <filter> [skip N][limit N]Show filtered documents based on index search> db.<collection>.count <filter>Show count rows according query filter> db.<collection>.ensureIndex <field> [true|{options}]Create a new index document field. For unique key, use true> db.<collection>.indexesList all indexes in this collection<filter> = <field> [=|>|>=|<|<=|!=|like|between] <jsonValue>Filter query syntax<filter> = (<filter> [and|or] <filter> [and|or] ...)Multi queries syntaxTry:> db.customers.insert { _id:1, name:"John Doe", age: 37 }> db.customers.ensureIndex name> db.customers.find name like "John"> db.customers.find name like "John" and _id between [0, 100] limit 10

说明:litedb 数据库和数据集无需创建,当不存在时执行 crud 代码会自动创建。

好了先到这里,我们就把测试项目准备好了,关于接口测试性能对比,下篇再续,敬请观看。

相关文章:

.NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)

WebAppDbTest 项目准备 项目准备1、.net cli 创建项目2、nuget 包引用和项目结构2.1、项目添加相关 nuget 包2.2、WebAppDbTest 项目结构 3、项目代码说明3.1、CSharp/C# 类文件说明3.2、json 配置文件说明 4、项目运行预览 数据库 .db 文件准备1、创建 SQLite 数据库1.1、在 W…...

2024 年,新程序员如何与AI共赢!!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…...

Debian 系统镜像下载

最近在看一些网络相关的文章需要用到 debian 11.x 的系统网上找了好多都发下载&#xff0c;在官网看一下 有个 11.8 的版本我无法下载&#xff0c;提示被最新的 debian-12.4.0 所代替&#xff0c;于是找到了这个链接 Index of /cdimage/unofficial/non-free/cd-including-fi…...

数据结构和算法(全)

1.了解数据结构和算法 1.1 二分查找 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;从而确定应该在左半部分还是右半部分继续查找。这个…...

Vue项目中WebSocket封装

WEBSOCKET 封装引入初始化使用 封装 utils下建立WebSocketManager.js class WebSocketManager {constructor() {this.url null;this.websocket null;this.isConnected false;this.listeners {onopen: [],onmessage: [],onclose: [],onerror: [],};this.reconnectionOptio…...

018 OpenCV 人脸检测

目录 一、环境 二、分类器原理 2.1、概述 2.2、工作原理 三、人脸检测代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17opencv-python 4.8.0.74 二、分类器原理 CascadeClassifier是OpenCV&#xff08;开源计算机视觉库&#xff09;中的一个强大的类…...

Etcd实战(一)-部署etcd集群

1 概述 etcd是一个高可用的分布式键值存储系统&#xff0c;是CoreOS&#xff08;现在隶属于Red Hat&#xff09;公司开发的一个开源项目。它提供了一个简单的接口来存储和检索键值对数据&#xff0c;并使用Raft协议实现了分布式一致性。etcd广泛应用于Docker、Kubernetes等分布…...

Python绘制一个简单的圣诞树

在Python中,你可以使用基本的打印语句和循环来绘制一个简单的圣诞树。以下是一个例子: def draw_christmas_tree(height):for i in range(height):print( * (height - i - 1) +...

【CANoe】CANoe中使用RS232

文章目录 1、CANoe中自带示例2、示例讲解2.1CANoe自带Port A和Port B通讯2.2CANoe自带Port A和串口助手通讯 1、CANoe中自带示例 我使用的事CANoe12&#xff0c;RS232路径如下&#xff1a; C:\Users\Public\Documents\Vector\CANoe\Sample Configurations 12.0.75\IO_HIL\RS23…...

Springboot内置Tomcat线程数优化

Springboot内置Tomcat线程数优化 # 等待队列长度&#xff0c;默认100。队列也做缓冲池用&#xff0c;但也不能无限长&#xff0c;不但消耗内存&#xff0c;而且出队入队也消耗CPU server.tomcat.accept-count1000 # 最大工作线程数&#xff0c;默认200。&#xff08;4核8g内存…...

vue+django 开发环境跨域前后端联调配置

vue环境是127.0.0.1:8080&#xff0c;django环境是127.0.0.1:8000 要解决url相对路径和Axios跨域权限问题。 注意&#xff1a;程序发起了一个 POST 请求&#xff0c;但请求的 URL 没有以斜杠结尾。Django 默认设置是无法执行重定向到带斜杠 URL的。例如&#xff1a;url http:/…...

Apache+mod_jk模块代理Tomcat容器

一、背景介绍 最近在看Tomcat运行架构原理, 正好遇到了AJP协议(Apache JServ Protocol). 顺道来研究下这个AJP协议和具体使用方法. 百度百科是这么描述AJP协议的: AJP&#xff08;Apache JServ Protocol&#xff09;是定向包协议。因为性能原因&#xff0c;使用二进制格式来传输…...

Nginx访问FTP服务器文件的时效性/安全校验

背景 FTP文件服务器在我们日常开发中经常使用&#xff0c;在项目中我们经常把FTP文件下载到内存中&#xff0c;然后转为base64给前端进行展示。如果excel中也需要导出图片&#xff0c;数据量大的情况下会直接返回一个后端的开放接口地址&#xff0c;然后在项目中对接口的参数进…...

【VSCode】自定义配置

VSCode自定义配置 Visual Studio Code (VSCode) 是一个强大的开源代码编辑器&#xff0c;支持丰富的自定义配置。下面是一些常见的自定义配置选项&#xff0c;你可以根据个人喜好和工作流程进行调整&#xff1a; 1. 主题和配色方案: 在 “settings.json” 中设置&#xff1a…...

SpringBoot整合Kafka (一)

&#x1f4d1;前言 本文主要讲了SpringBoot整合Kafka文章⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句&#xff1a;努力一点&#xff0c;优秀一点 目录 文章目录 &…...

随机分词与tokenizer(BPE->BBPE->Wordpiece->Unigram->sentencepiece->bytepiece)

0 tokenizer综述 根据不同的切分粒度可以把tokenizer分为: 基于词的切分&#xff0c;基于字的切分和基于subword的切分。 基于subword的切分是目前的主流切分方式。subword的切分包括: BPE(/BBPE), WordPiece 和 Unigram三种分词模型。其中WordPiece可以认为是一种特殊的BPE。完…...

成都工业学院Web技术基础(WEB)实验四:CSS3布局应用

写在前面 1、基于2022级计算机大类实验指导书 2、代码仅提供参考&#xff0c;前端变化比较大&#xff0c;按照要求&#xff0c;只能做到像&#xff0c;不能做到一模一样 3、图片和文字仅为示例&#xff0c;需要自行替换 4、如果代码不满足你的要求&#xff0c;请寻求其他的…...

TikTok科技趋势:平台如何引领数字社交革命?

TikTok作为一款颠覆性的短视频应用&#xff0c;不仅改变了用户的娱乐方式&#xff0c;更在数字社交领域引领了一场革命。本文将深入探讨TikTok在科技趋势方面的引领作用&#xff0c;分析其在数字社交革命中的关键角色&#xff0c;以及通过技术创新如何不断满足用户需求&#xf…...

【上海大学数字逻辑实验报告】六、时序电路

一、 实验目的 掌握同步二进制计数器和移位寄存器的原理。学会用分立元件构成2位同步二进制加计数器。学会在Quartus II上设计单向移位寄存器。学会在Quartus II上设计环形计数器。 二、 实验原理 同步计数器是指计数器中的各触发器的时钟脉冲输入端连接在一起&#xff0c;接…...

docker版zerotier-planet服务端搭建

1:ZeroTier 介绍2:为什么要自建PLANET 服务器3:开始安装 3.1:准备条件 3.1.1 安装git3.1.2 安装docker3.1.3 启动docker3.2:下载项目源码3.3:执行安装脚本3.4 下载 planet 文件3.5 新建网络 3.5.1 创建网络4.客户端配置 4.1 Windows 配置 4.2 加入网络4.2 Linux 客户端4.…...

【Spring教程28】Spring框架实战:从零开始学习SpringMVC 之 请求与请求参数详解

目录 1 设置请求映射路径1.1 环境准备 1.2 问题分析1.3 设置映射路径 2 请求参数2.1 环境准备2.2 参数传递2.2.1 GET发送单个参数2.2.2 GET发送多个参数2.2.3 GET请求中文乱码2.2.4 POST发送参数2.2.5 POST请求中文乱码 欢迎大家回到《Java教程之Spring30天快速入门》&#xff…...

node.js和浏览器之间的区别

node.js是什么 Node.js是一种基于Chrome V8引擎的JavaScript运行环境&#xff0c;可以在服务器端运行JavaScript代码 Node.js 在浏览器之外运行 V8 JavaScript 引擎。 这使得 Node.js 非常高效。 浏览器如何运行js代码 nodejs运行环境 在浏览器中&#xff0c;大部分时间你所…...

【python并发任务的几种方式】

文章目录 1 Process:2 Thread:3 ThreadPoolExecutor:4 各种方式的优缺点&#xff1a;5 线程与进程的结束方式5.1 线程结束的几种方式5.2 进程的结束方式 6 应用场景效率对比 在Python中&#xff0c;有几种方法可以处理并行执行任务。其中&#xff0c;Process、Thread和ThreadPo…...

使用ROS模板基于ECS和RDS创建WordPress环境

本文教程介绍如何使用ROS模板基于ECS和RDS&#xff08;Relational Database Service&#xff09;创建WordPress环境。 前提条件 如果您是首次使用ROS&#xff0c;必须先开通ROS服务。ROS服务免费&#xff0c;开通服务不会产生任何费用。 背景信息 WordPress是使用PHP语言开…...

龙迅LT2611UXC 双PORT LVDS转HDMI(2.0)+音频

描述&#xff1a; LT2611UXC是一个高性能的LVDS到HDMI2.0的转换器&#xff0c;用于STB&#xff0c;DVD应用程序。 LVDS输入可配置为单端口或双端口&#xff0c;有1个高速时钟通道&#xff0c;3~4个高速数据通道&#xff0c;最大运行1.2Gbps/通道&#xff0c;可支持高达9.6Gbp…...

websocket和SSE通信示例(无需安装任何插件)

websocket和SSE通信示例&#xff08;无需安装任何插件&#xff09; 源码示例&#xff08;两种方案任意切换&#xff09; data(){return {heartBeatInterval:5000,// 心跳间隔时间&#xff0c;单位为毫秒webSocket:null,heartBeatTimer:null,} }, mounted() {// this.initWebS…...

计算机网络(三)

&#xff08;十一&#xff09;路由算法 A、路由算法分类 动态路由和静态路由 静态路由&#xff1a;人工配制&#xff0c;路由信息更新慢&#xff0c;优先级高。这种在实际网络中要投入成本大&#xff0c;准确但是可行性弱。 动态路由&#xff1a;路由更新快&#xff0c;自动…...

HttpURLConnection OOM问题记录

使用HttpURLConnection 上传大文件&#xff0c;会出现内存溢出问题&#xff1a; 观察HttpURLConnection 源码&#xff1a; Overridepublic synchronized OutputStream getOutputStream() throws IOException {connecting true;SocketPermission p URLtoSocketPermission(th…...

WT588F02B单片机语音芯片在磁疗仪中的应用介绍

随着健康意识的普及和科技的发展&#xff0c;磁疗仪作为一种常见的理疗设备&#xff0c;受到了广大用户的关注。为了提升用户体验和操作便捷性&#xff0c;唯创知音WT588F02B单片机语音芯片被成功应用于磁疗仪中。这一结合将为磁疗仪带来智能化的语音交互功能&#xff0c;为用户…...

深度学习——第5章 神经网络基础知识

第5章 神经网络基础知识 目录 5.1 由逻辑回归出发 5.2 损失函数 5.3 梯度下降 5.4 计算图 5.5总结 在第1课《深度学习概述》中&#xff0c;我们介绍了神经网络的基本结构&#xff0c;了解了神经网络的基本单元组成是神经元。如何构建神经网络&#xff0c;如何训练、优化神…...