我有一个带有一个名为tbl_invent的表的sqlite数据库,在表单加载时,它使用表中的内容填充datagridview。问题是我有字段名称成本和sell_price有小数,当表单加载时它只显示数字而不是小数。
示例:
表= 1.75,DGV = 1.00
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
connect()
Dim da As New SQLiteDataAdapter("select * from tbl_Invent", connection)
Dim ds As New DataSet
da.Fill(ds, "tbl_Invent")
DataGridView1.DataSource = ds
DataGridView1.DataMember = "tbl_Invent"
DataGridView1.Columns(6).ValueType = GetType(Single)
DataGridView1.Columns(6).DefaultCellStyle.Format = "N2"
DataGridView1.Columns(7).ValueType = GetType(Single)
DataGridView1.Columns(7).DefaultCellStyle.Format = "N2"
connection.Close()
da.Dispose()
End Sub
我已经检查了字段类型它是否正确“整数”,我也尝试了“GetType(单一)”和“GetType(十进制)”但仍然相同。任何人都可以指出我正确的方向?谢谢。
来自评论:
SQLite中没有其他类型。在SQLite中只有“Text”,“Integer”,“Real”和“Blob”,它表示整数可以有小数。
答案 0 :(得分:4)
您没有指明您使用的是哪个数据库提供程序,但标准提供程序(来自SQLite开发人员)会看到Integer
并将数据映射到NET Int32
类型,而不是允许小数。 Real
会像Decimal
那样保存分数。
there is no other type in SQLite. there is only "Text", "Integer", "Real" and "Blob"
这是真的,但它适用于SQLite DB,而不是DB Provider。标准DB提供程序巧妙编写,能够将4种基本类型转换为各种.NET类型,以便实际存储类型/格式成为实现细节。
提供者代码包括许多步骤,查找表,子系统,字典和执行转换的方法。甚至有一种方法可以定义自定义类型名称。以下是对工作的通用解释。
Byte,SByte
INT8,INTEGER8,TINYSINT(SByte)
UINT8,UNSIGNEDINTEGER8,TINYINT(字节)
积分(短,长,签名,无符号等)
BIGINT,BIGUINT,COUNTER,IDENTITY,INT,INT16,INT32,INT64,INTEGER,INTEGER16,INTEGER32,INTEGER64,LONG,SMALLINT,SMALLUINT,UINT,UINT16,UINT32,UINT64,ULONG,UNSIGNEDINTEGER,UNSIGNEDINTEGER16,UNSIGNEDINTEGER32,UNSIGNEDINTEGER64
<强>布尔强>
BIT,BOOL,BOOLEAN,LOGICAL,YESNO
文字/字符串强>
CHAR,CLOB,LONGCHAR,LONGTEXT,LONGVARCHAR,MEMO,NCHAR,NOTE,NTEXT,NVARCHAR,STRING,TEXT,VARCHAR,VARCHAR2
<强>数字强>
DOUBLE,FLOAT,REAL;单(单)
<强>十进制强>
CURRENCY,DECIMAL,MONEY,NUMBER,NUMERIC
<强> BLOB 强>
BINARY,BLOB,GENERAL,IMAGE,OLEOBJECT,RAW,VARBINARY
<强>日期/时间强>
DATE,DATETIME,SMALLDATE,TIME,TIMESTAMP
<强> GUID 强>
GUID,UNIQUEIDENTIFIER
来源:SQLiteDbTypeMap
SQLiteConvert.cs
(版本1.0.103; 2016年9月)。
本质上,DBProvider 以适当的SQLite类型存储数据,但当它读取后,它会使用您在表定义中使用的类型来转换数据返回NET类型。 SQLite提供程序包含一个大型SQLiteConvert
类,可以为您完成所有转换。
我无法在野外发现这一点,尽管它似乎是SQLite爱好者的常识。大多数网站只是重新格式化SQLite网站内容。它可能会记录在帮助文件中,但我的主题没有内容。根据列表,很容易意外地使用有效名称并发现它有效。
该列表包含其他数据库使用的最常见符号,以及一些NET类型。例如,Boolean
可以定义为BIT, BOOL, BOOLEAN, LOGICAL or YESNO
。因此,此表定义合法且功能齐全:
CREATE TABLE LiteColTypes (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
Name TEXT,
ItemDate DATETIME,
Char3 CHAR (3),
UINT32 UINT32,
Value INT16,
VarChar5 VARCHAR (5),
GCode GUID,
Price DECIMAL,
ItemImg IMAGE,
Active BOOL,
NotActive YESNO
);
有几点需要注意,有些DateTime
选项很有用。
该代码来自此代码:
/// <summary>
/// Builds and returns a map containing the database column types
/// recognized by this provider.
/// </summary>
/// <returns>
/// A map containing the database column types recognized by this
/// provider.
/// </returns>
private static SQLiteDbTypeMap GetSQLiteDbTypeMap()
{
return new SQLiteDbTypeMap(new SQLiteDbTypeMapping[] {
new SQLiteDbTypeMapping("BIGINT", DbType.Int64, false),
new SQLiteDbTypeMapping("BINARY", DbType.Binary, false),
new SQLiteDbTypeMapping("BIT", DbType.Boolean, true),
new SQLiteDbTypeMapping("BLOB", DbType.Binary, true),
new SQLiteDbTypeMapping("BOOL", DbType.Boolean, false),
new SQLiteDbTypeMapping("BOOLEAN", DbType.Boolean, false),
...
new SQLiteDbTypeMapping("GUID", DbType.Guid, false),
new SQLiteDbTypeMapping("IMAGE", DbType.Binary, false)
... (many more)
保留了XML注释,因为它具有启发性和权威性:
构建并返回包含此提供程序识别的数据库列类型的地图。 (强调我的)。
DbType
对此过程至关重要。
上面的SQLiteDbTypeMap
将它识别的许多列名称与DbType
相关联,后者用于确定要返回的.NET数据类型。该列表非常全面,可以为您转换除1或2之外的所有类型。
例如,请注意GUID
和IMAG
*都存储为BLOB
,但GUID
类型名称与不同的DbType
允许 BLOB以不同于IMAGE
BLOB的方式返回。
您还可以通过连接对象指定类型。空间和范围不允许解释,但有点单调乏味,它允许您提供自定义类型名称的数据类型。
存储数据时,你无需担心应该如何存储数据。数据库提供程序将使用传递的DbType
来查找要使用的SQLite类型(Affinity&#34;)。如果您使用AddWithValue
或(过时的)Add(object, object)
重载,则DBProvider将猜测该类型。它很擅长猜测,但不要这样做。
因此,不需要进行此转换:
cmd.Parameters.Add("@g", DbType.Binary).Value = myGuid.ToByteArray();
使用与任何其他数据库相同的代码:
' // add trailing semicolons for c#
cmd.Parameters.Add("@n", DbType.String).Value = "Ziggy"
cmd.Parameters.Add("@dt", DbType.DateTime).Value = DateTime.Now
cmd.Parameters.Add("@c3", DbType.StringFixedLength, 3).Value = "XYZ123" '// see notes
cmd.Parameters.Add("@u", DbType.UInt16).Value = 3
cmd.Parameters.Add("@g", DbType.Guid).Value = myGuid
cmd.Parameters.Add("@p", DbType.Decimal).Value = 3.14D
'// 'ToByteArray()' is an extension method to convert
cmd.Parameters.Add("@img", DbType.Binary).Value = myImg.ToByteArray()
cmd.Parameters.Add("@act", DbType.Boolean).Value = True
注意:
DbType
,而不是您认为 的保存方式(例如DbType.Guid
,而不是Binary
{{1} }})。提供商将执行大多数转化。Guid
所以需要字节数组转换 DbType.Image
字段的大小不会限制保存的字符数。这似乎是一个错误,因为保存的字符多于定义的字符可以防止加载行。Char()/VarChar()
反向运行:尝试传递超出范围的值(例如,对于UInt16为-5)将导致UInt16
。但它会返回Overflow Exception
这样一个已存储的值。65531
)似乎并不重要。内部表格提供固定的精度和尺寸。Decimal(9,2)
。无需传递特定格式的字符串。提供者知道事情。 (参见下面的日期时间选项。)DbType.DateTime
。 两个不同的查找表用于保存与读取数据,它们的共同点是.Value = DateTime.Now.Date
,这就是重要的原因。使用正确的数据可确保数据可以进行往返。避免使用DbType
。
加载数据没有什么特别之处:
AddWithValue
DGV正确识别并显示GUID,图像和布尔列。每个 // Dim SQL = "SELECT * FROM LiteColTypes" ' for VB
string SQL = "SELECT * FROM LiteColTypes";
...
dbCon.Open();
Dim dt As New DataTable();
dt.Load(cmd.ExecuteReader());
dgv.DataSource = dt;
的数据类型都符合预期:
DataColumn
请注意, Guid 和图像项目均存储为 Name ---> System.String (maxLen = 2147483647)
ItemDate ---> System.DateTime
Char3 ---> System.String (maxLen = 3)
UINT16 ---> System.UInt16
VarChar5 ---> System.String (maxLen = 5)
GCode ---> System.Guid
Price ---> System.Decimal
ItemImg ---> System.Byte[]
Active ---> System.Boolean
NotActive ---> System.Boolean
,但返回方式不同。 活动(BLOB
)和 NotActive (BOOL
)使用了不同的类型名称,但返回相同的数据类型。一切都按预期工作。
YESNO
作为列类型名称并不像预期的那样完全正常工作。它不会解析TIME
(DateTime.Now.TimeofDay
)。该表将TIME映射到Timespan
。
请勿使用 DbType.DateTime
或DbType.DateTime2
。转换器查找中缺少这些内容,因此数据以无效格式(版本1.0.103.0)存储为文本。
SQLite NET Provider不支持一种日期格式。保存为UTC时,数据包含指示符。但是,无论是保存为本地还是UTC,.DateTimeOffset
始终都会将作为Kind
返回。解决此问题的部分原因是将Unspecified
添加到您的连接字符串中:
datetimekind
这会为所有`...;datetimekind=Utc;`
`...;datetimekind=Local;`
值返回设置Kind
,但不转换值。
this 的补救措施是使用(相对)新的DateTime
连接标志。当保存时,这将转换日期以匹配连接的BindDateTimeWithKind
:
DateTimeKind
虽然传递了本地日期,但Private LiteConnStr = "Data Source='C:\Temp\demo.db';Version=3;DateTimeKind=Utc;"
...
Dim dt As New DateTime(2011, 2, 11, 11, 22, 33, 444, DateTimeKind.Local)
Using dbCon = New SQLiteConnection(LiteConnStr)
dbCon.Flags = SQLiteConnectionFlags.Default Or
SQLiteConnectionFlags.BindDateTimeWithKind
...
cmd.Parameters.Add("@dt", DbType.DateTime).Value = dt
' == 2011-02-11 17:22:33.444Z note the hour
会将其保存为UTC以匹配连接。由于&#34; DateTimeKind = Utc;&#34;返回UTC日期。连接设置。
请注意,BindDateTimeWithKind
适用于读取的日期,DateTimeKind
在保存日期时起作用。个别地,他们似乎会使事情变得更糟; 一起整个数据库变为基于UTC(或本地),日期统一保存并读取为BindDateTimeWithKind
- 您无需执行任何操作。
Kind
可能很繁琐,要在连接字符串中指定它们:
ConnectionFlags
限制/问题
统一connx = "...;datetimekind=Utc;flags='Default, BindDateTimeWithKind';"
治疗适用于Kind
,至少与Dapper一起使用。但是,在使用DbDataReader
时,日期的DataTable
仍为未指定。这显然是由于Kind
中的DateTimeMode
属性,并且微软可能不会假设列中的所有日期始终都是DataColumn
。这也体现在其他数据库中。
使用UTC或本地连接时,提供程序单独保留Unspecified(这也适用于查询中的日期)。所以不应该有任何不受欢迎的额外转换:UTC日期阅读和伪装&#39;在Kind
中未指定未在更新中再次转换 。
与传统智慧相反。日期并不总是只保存为TEXT;为了节省一点空间,您可以保存刻度值。由于这些没有时区指示符,因此DataTable
相关选项非常有用。要启用Ticks,请使用Kind
连接字符串选项:
DateTimeFormat
其他Private LiteConnStr = "...;datetimekind=Utc;DateTimeFormat=Ticks;..."
'e.g: 634939900800000000
选项包括 CurrentCulture , ISO8601 (默认), JulianDay 和 UnixEpoch 。无需更改列类型名称即可使用其中一种格式。它仍然是一个日期,SQLite Provider根据连接标志处理实现细节。
UI浏览器
许多SQLite UI浏览器似乎只知道四种规范类型。也许这是故意的,但这限制了它们对.NET开发人员的实用性,并隐藏了.NET提供程序的功能。
SQLiteStudio(版本:3.1.0)提供了更多,但它似乎并不知道完整列表,因为缺少一些非常有用的列表(例如GUID,IMAGE,SINGLE,整数变体) 。
它 允许你输入你想要的任何类型名称,所以获利!
DateTimeFormat
相关联,后者确定实际的返回数据类型DBType
可确保数据进行往返DbType
和DateTimeKind
选项允许自动,统一的TimeZone日期存储最重要的是,NET提供商使实际存储成为实现细节。