Ily*_*nin 5 c# sqlite dapper .net-core
我对 .Net 中的 Sqlite 没有太多经验,但我看到的行为很奇怪。假设我们有一个 .Net 核心应用程序,其中包含以下内容project.json:
{
"version": "1.0.0-*",
"buildOptions": {
"debugType": "portable",
"emitEntryPoint": true
},
"dependencies": {
"Microsoft.Data.Sqlite": "1.0.0",
"Dapper": "1.50.2"
},
"frameworks": {
"netcoreapp1.0": {
"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.0"
}
},
"imports": "dnxcore50"
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们还有一个简单的类Item:
public class Item
{
public Item() { }
public Item(int id, string name, decimal price)
{
this.Id = id;
this.Name = name;
this.Price = price;
}
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我创建一个内存数据库并用数据填充它(使用 Dapper):
var connection = new SqliteConnection("Data Source=:memory:");
connection.Open();
connection.Execute("CREATE TABLE IF NOT EXISTS Items(Id INT, Name NVARCHAR(50), Price DECIMAL)");
var items = new List<Item>
{
new Item(1, "Apple", 3m),
new Item(2, "Banana", 1.4m)
};
connection.Execute("INSERT INTO Items(Id, Name, Price) VALUES (@Id, @Name, @Price)", items);
Run Code Online (Sandbox Code Playgroud)
然后我尝试从Items表中读取:
var dbItems = connection.Query<Item>("SELECT Id, Name, Price FROM Items").ToList();
Run Code Online (Sandbox Code Playgroud)
当我运行解决方案时,出现以下异常:
未处理的异常:System.InvalidOperationException:解析第 2 列时出错(Price=1.4 - Double)---> System.Invali dCastException:无法将“System.Double”类型的对象转换为“System.Int64”类型。
好的,然后我尝试使用Microsoft.Data.Sqlite获取数据:
var command = connection.CreateCommand();
command.CommandText = "SELECT Price FROM Items";
var reader = command.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(reader[0].GetType());
}
Run Code Online (Sandbox Code Playgroud)
结果我得到:
System.Int64 // Price = 3
System.Double // Price = 1.4
Run Code Online (Sandbox Code Playgroud)
我尝试使用十进制价格在真实数据库上运行查询,返回的数据类型是正确的并且总是十进制(如预期的那样)。
我应该进一步挖掘什么方向?我的内存数据库有问题吗?如何使它与小数一致?
在 SQLite 中,如果您创建具有数字/小数列数据类型的表,则它与数字类型关联相关联,并且其默认行为是如果值没有小数则存储整数,或者如果值包含小数则存储实数。这有助于节省字节存储,因为最常用的整数值(中小型应用程序小于一百万个值)需要的字节数比实际数据类型少:
整数(大约):
针对 8 字节真实 IEEE 数据类型
如果您需要始终存储实数,则有必要声明 float/real 数据类型才能被视为实数类型关联,因此即使您将整数发送到 SQLite,它也会存储为实数
来源: https: //sqlite.org/datatype3.html
我知道 real 可能不精确,但我已经使用 C# Decimal 数据类型和 SQLite 以及 wal 模式下磁盘中的数据库进行了一些测试,并且如果所有操作都在 C# 中进行,我从未遇到过舍入错误。但是当我直接在 SQLite 中进行一些计算时,由于 2 整数除法,我得到了一些舍入错误和一些错误的计算
我使用 EF6 和 Dapper 读取/写入数值(来自 SQLite 的整数/实数)并且从未出现错误。
现在,我计划利用 SQLite 数字行为通过简洁的 TypeHandler 来节省磁盘空间,因此我可以复制 SQL ServerMoney实现(在内部,SQL Server 保存一个 8 字节整数,并在加载到内存时除以 10000):
public class NumericTypeHandler : SqlMapper.TypeHandler<decimal>
{
public override void SetValue(IDbDataParameter parameter, decimal value)
{
parameter.Value = (long)(value / 10000);
}
public override decimal Parse(object value)
{
return ((decimal)value)/10000M;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我设置了 datetime UnixEpoch 实现来节省磁盘空间并提高性能
笔记:
SQLite 可以在低需求的 ASP.NET 应用程序中处理数十个用户,技巧是使用 pragmas 指令和其他东西来调整 SQLite:
我还在 C# 方面做了一些增强:
避免保存不必要的数据(错误日志、电子邮件 html 文本)
我认为如果您计划使用 SQLite 作为后端,您应该使用像 EFx 或 Dapper 这样的 ORM。使用 dapper,您需要创建自己的微框架以节省开发时间(基本 CRUD 功能和 Linq 查询转换)。
我发现的最好的工具是https://github.com/linq2db/linq2db,您可以使用 linq 来访问数据库,并且 linq 的速度和易用性非常好。并且可以实现CRUD功能。
如果这个答案有帮助我会很高兴
问候
| 归档时间: |
|
| 查看次数: |
5160 次 |
| 最近记录: |