提交 c63220ef 编写于 作者: 智能大石头's avatar 智能大石头

improvement: 改进SQLite中用于匹配建表sql的正则表达式,以文本开头或逗号来高效切分

上级 a7fa3375
......@@ -528,12 +528,21 @@ internal class SQLiteMetaData : FileDbMetaData
return list;
}
static readonly Regex _reg = new(@"[\(,]\s*(\[\w+\]|\w+)
\s+(\w+(?:\(\d+(?:,\s*\d+)?\))?)
\s*([^,]*)?",
static readonly Regex _reg = new("""
(?:^|,)\s*(\[\w+\]|\w+)
\s+(\w+(?:\(\d+(?:,\s*\d+)?\))?)
\s*([^,]*)?
""",
RegexOptions.Singleline | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline | RegexOptions.IgnoreCase);
public void ParseColumns(IDataTable table, String sqlCreateTable)
{
if (sqlCreateTable.StartsWithIgnoreCase("create table"))
{
var p1 = sqlCreateTable.IndexOf('(');
var p2 = sqlCreateTable.LastIndexOf(')');
if (p1 > 0 && p2 > 0) sqlCreateTable = sqlCreateTable.Substring(p1 + 1, p2 - p1 - 1);
}
var ms = _reg.Matches(sqlCreateTable);
foreach (Match m in ms)
{
......
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Serialization;
using NewLife.Collections;
namespace XCode.DataAccessLayer
namespace XCode.DataAccessLayer;
/// <summary>字段构架</summary>
[Serializable]
[DisplayName("字段模型")]
[Description("字段模型")]
[XmlRoot("Column")]
class XField : SerializableDataMember, IDataColumn, ICloneable
{
/// <summary>字段构架</summary>
[Serializable]
[DisplayName("字段模型")]
[Description("字段模型")]
[XmlRoot("Column")]
class XField : SerializableDataMember, IDataColumn, ICloneable
#region 属性
/// <summary>名称</summary>
[XmlAttribute]
[DisplayName("名称")]
[Description("名称")]
public String Name { get; set; }
/// <summary>列名</summary>
[XmlAttribute]
[DisplayName("列名")]
[Description("列名")]
public String ColumnName { get; set; }
/// <summary>数据类型</summary>
[XmlAttribute]
[DisplayName("数据类型")]
[Description("数据类型")]
public Type DataType { get; set; }
/// <summary>原始数据类型</summary>
[XmlAttribute]
[DisplayName("原始类型")]
[Description("原始类型")]
public String RawType { get; set; }
/// <summary>元素类型</summary>
[XmlAttribute]
[DisplayName("元素类型")]
[Description("元素类型")]
public String ItemType { get; set; }
/// <summary>映射,表间关联,格式Role.Id.Name</summary>
[XmlAttribute]
[DisplayName("映射")]
[Description("映射,表间关联")]
public String Map { get; set; }
/// <summary>标识</summary>
[XmlAttribute]
[DisplayName("标识")]
[Description("标识")]
public Boolean Identity { get; set; }
/// <summary>主键</summary>
[XmlAttribute]
[DisplayName("主键")]
[Description("主键")]
public Boolean PrimaryKey { get; set; }
/// <summary>是否主字段。主字段作为业务主要字段,代表当前数据行意义</summary>
[XmlAttribute]
[DisplayName("主字段")]
[Description("主字段")]
public Boolean Master { get; set; }
/// <summary>长度</summary>
[XmlAttribute]
[DisplayName("长度")]
[Description("长度")]
public Int32 Length { get; set; }
/// <summary>精度</summary>
[XmlAttribute]
[DisplayName("精度")]
[Description("精度")]
public Int32 Precision { get; set; }
/// <summary>位数</summary>
[XmlAttribute]
[DisplayName("位数")]
[Description("位数")]
public Int32 Scale { get; set; }
/// <summary>允许空</summary>
[XmlAttribute]
[DisplayName("允许空")]
[Description("允许空")]
public Boolean Nullable { get; set; }
/// <summary>默认值</summary>
[XmlAttribute]
[DisplayName("默认值")]
[Description("默认值")]
public String DefaultValue { get; set; }
private String _Description;
/// <summary>描述</summary>
[XmlAttribute]
[DisplayName("描述")]
[Description("描述")]
public String Description
{
#region 属性
/// <summary>名称</summary>
[XmlAttribute]
[DisplayName("名称")]
[Description("名称")]
public String Name { get; set; }
/// <summary>列名</summary>
[XmlAttribute]
[DisplayName("列名")]
[Description("列名")]
public String ColumnName { get; set; }
/// <summary>数据类型</summary>
[XmlAttribute]
[DisplayName("数据类型")]
[Description("数据类型")]
public Type DataType { get; set; }
/// <summary>原始数据类型</summary>
[XmlAttribute]
[DisplayName("原始类型")]
[Description("原始类型")]
public String RawType { get; set; }
/// <summary>元素类型</summary>
[XmlAttribute]
[DisplayName("元素类型")]
[Description("元素类型")]
public String ItemType { get; set; }
/// <summary>映射,表间关联,格式Role.Id.Name</summary>
[XmlAttribute]
[DisplayName("映射")]
[Description("映射,表间关联")]
public String Map { get; set; }
/// <summary>标识</summary>
[XmlAttribute]
[DisplayName("标识")]
[Description("标识")]
public Boolean Identity { get; set; }
/// <summary>主键</summary>
[XmlAttribute]
[DisplayName("主键")]
[Description("主键")]
public Boolean PrimaryKey { get; set; }
/// <summary>是否主字段。主字段作为业务主要字段,代表当前数据行意义</summary>
[XmlAttribute]
[DisplayName("主字段")]
[Description("主字段")]
public Boolean Master { get; set; }
/// <summary>长度</summary>
[XmlAttribute]
[DisplayName("长度")]
[Description("长度")]
public Int32 Length { get; set; }
/// <summary>精度</summary>
[XmlAttribute]
[DisplayName("精度")]
[Description("精度")]
public Int32 Precision { get; set; }
/// <summary>位数</summary>
[XmlAttribute]
[DisplayName("位数")]
[Description("位数")]
public Int32 Scale { get; set; }
/// <summary>允许空</summary>
[XmlAttribute]
[DisplayName("允许空")]
[Description("允许空")]
public Boolean Nullable { get; set; }
/// <summary>默认值</summary>
[XmlAttribute]
[DisplayName("默认值")]
[Description("默认值")]
public String DefaultValue { get; set; }
private String _Description;
/// <summary>描述</summary>
[XmlAttribute]
[DisplayName("描述")]
[Description("描述")]
public String Description
get { return _Description; }
set
{
get { return _Description; }
set
{
if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
_Description = value;
}
if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
_Description = value;
}
#endregion
#region 扩展属性
/// <summary>表</summary>
[XmlIgnore, IgnoreDataMember]
public IDataTable Table { get; set; }
private String _DisplayName;
/// <summary>显示名</summary>
[XmlAttribute]
[DisplayName("显示名")]
[Description("显示名")]
public String DisplayName
}
#endregion
#region 扩展属性
/// <summary>表</summary>
[XmlIgnore, IgnoreDataMember]
public IDataTable Table { get; set; }
private String _DisplayName;
/// <summary>显示名</summary>
[XmlAttribute]
[DisplayName("显示名")]
[Description("显示名")]
public String DisplayName
{
get
{
get
{
if (String.IsNullOrEmpty(_DisplayName)) _DisplayName = ModelResolver.Current.GetDisplayName(Name, _Description);
return _DisplayName;
}
if (String.IsNullOrEmpty(_DisplayName)) _DisplayName = ModelResolver.Current.GetDisplayName(Name, _Description);
return _DisplayName;
}
}
/// <summary>扩展属性</summary>
[XmlIgnore, IgnoreDataMember]
[Category("扩展")]
[DisplayName("扩展属性")]
[Description("扩展属性")]
public IDictionary<String, String> Properties { get; } = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
#endregion
#region 构造
/// <summary>实例化</summary>
public XField() { }
#endregion
#region 方法
/// <summary>重新计算修正别名。避免与其它字段名或表名相同,避免关键字</summary>
/// <returns></returns>
public IDataColumn Fix()
{
return ModelResolver.Current.Fix(this);
}
/// <summary>扩展属性</summary>
[XmlIgnore, IgnoreDataMember]
[Category("扩展")]
[DisplayName("扩展属性")]
[Description("扩展属性")]
public IDictionary<String, String> Properties { get; } = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
#endregion
#region 构造
///// <summary>实例化</summary>
//public XField() { }
#endregion
#region 方法
/// <summary>重新计算修正别名。避免与其它字段名或表名相同,避免关键字</summary>
/// <returns></returns>
public IDataColumn Fix()
{
return ModelResolver.Current.Fix(this);
}
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString()
{
if (!String.IsNullOrEmpty(DisplayName) && DisplayName != Name)
return $"Name={ColumnName} DataType={DataType?.Name} RawType={RawType} DisplayName={DisplayName}";
else
return $"Name={ColumnName} DataType={DataType?.Name} RawType={RawType}";
}
#endregion
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString()
{
if (!String.IsNullOrEmpty(DisplayName) && DisplayName != Name)
return $"Name={ColumnName} DataType={DataType?.Name} RawType={RawType} DisplayName={DisplayName}";
else
return $"Name={ColumnName} DataType={DataType?.Name} RawType={RawType}";
}
#endregion
#region ICloneable 成员
/// <summary>克隆</summary>
/// <returns></returns>
Object ICloneable.Clone() => Clone(Table);
#region ICloneable 成员
/// <summary>克隆</summary>
/// <returns></returns>
Object ICloneable.Clone() => Clone(Table);
/// <summary>克隆</summary>
/// <param name="table"></param>
/// <returns></returns>
public IDataColumn Clone(IDataTable table)
{
var field = base.MemberwiseClone() as XField;
field.Table = table;
//field.Fix();
/// <summary>克隆</summary>
/// <param name="table"></param>
/// <returns></returns>
public IDataColumn Clone(IDataTable table)
{
var field = base.MemberwiseClone() as XField;
field.Table = table;
//field.Fix();
return field;
}
#endregion
return field;
}
#endregion
}
\ No newline at end of file
......@@ -7,241 +7,240 @@ using System.Xml.Serialization;
using NewLife.Collections;
using NewLife.Xml;
namespace XCode.DataAccessLayer
namespace XCode.DataAccessLayer;
/// <summary>表模型</summary>
[DebuggerDisplay("{Name} {Description}")]
[Serializable]
[DisplayName("表模型")]
[Description("表模型")]
[XmlRoot("Table")]
class XTable : IDataTable, ICloneable, IXmlSerializable
{
/// <summary>表模型</summary>
[DebuggerDisplay("{Name} {Description}")]
[Serializable]
[DisplayName("表模型")]
[Description("表模型")]
[XmlRoot("Table")]
class XTable : IDataTable, ICloneable, IXmlSerializable
#region 基本属性
///// <summary>编号</summary>
//[XmlAttribute]
//[DisplayName("编号")]
//[Description("编号")]
//public Int32 ID { get; set; }
/// <summary>名称</summary>
[XmlAttribute]
[DisplayName("名称")]
[Description("名称")]
public String Name { get; set; }
/// <summary>表名</summary>
[XmlAttribute]
[DisplayName("表名")]
[Description("表名")]
public String TableName { get; set; }
private String _Description;
/// <summary>描述</summary>
[XmlAttribute]
[DisplayName("描述")]
[Description("描述")]
public String Description
{
#region 基本属性
///// <summary>编号</summary>
//[XmlAttribute]
//[DisplayName("编号")]
//[Description("编号")]
//public Int32 ID { get; set; }
/// <summary>名称</summary>
[XmlAttribute]
[DisplayName("名称")]
[Description("名称")]
public String Name { get; set; }
/// <summary>表名</summary>
[XmlAttribute]
[DisplayName("表名")]
[Description("表名")]
public String TableName { get; set; }
private String _Description;
/// <summary>描述</summary>
[XmlAttribute]
[DisplayName("描述")]
[Description("描述")]
public String Description
get { return _Description; }
set
{
get { return _Description; }
set
{
if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
_Description = value;
}
if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
_Description = value;
}
}
/// <summary>是否视图</summary>
[XmlAttribute]
[DisplayName("是否视图")]
[Description("是否视图")]
public Boolean IsView { get; set; }
/// <summary>所有者</summary>
[XmlAttribute]
[DisplayName("所有者")]
[Description("所有者")]
public String Owner { get; set; }
/// <summary>连接名</summary>
[XmlAttribute]
[DisplayName("连接名")]
[Description("连接名")]
public String ConnName { get; set; }
/// <summary>数据库类型</summary>
[XmlAttribute]
[DisplayName("数据库类型")]
[Description("数据库类型")]
public DatabaseType DbType { get; set; }
/// <summary>基类</summary>
[XmlAttribute]
[DisplayName("基类")]
[Description("基类")]
public String BaseType { get; set; }
/// <summary>仅插入的日志型数据</summary>
[XmlAttribute]
[DisplayName("只写")]
[Description("只写")]
public Boolean InsertOnly { get; set; }
#endregion
#region 扩展属性
/// <summary>字段集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
[Category("集合")]
[DisplayName("字段集合")]
[Description("字段集合")]
public List<IDataColumn> Columns { get; private set; }
/// <summary>索引集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
[Category("集合")]
[DisplayName("索引集合")]
[Description("索引集合")]
public List<IDataIndex> Indexes { get; private set; }
/// <summary>主字段。主字段作为业务主要字段,代表当前数据行意义</summary>
[XmlIgnore, IgnoreDataMember]
public IDataColumn Master => Columns.FirstOrDefault(e => e.Master) ?? Columns.FirstOrDefault(e => e.PrimaryKey);
/// <summary>主键集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
public IDataColumn[] PrimaryKeys => Columns.FindAll(item => item.PrimaryKey).ToArray();
private String _DisplayName;
/// <summary>显示名</summary>
[XmlAttribute]
[DisplayName("显示名")]
[Description("显示名")]
public String DisplayName
/// <summary>是否视图</summary>
[XmlAttribute]
[DisplayName("是否视图")]
[Description("是否视图")]
public Boolean IsView { get; set; }
/// <summary>所有者</summary>
[XmlAttribute]
[DisplayName("所有者")]
[Description("所有者")]
public String Owner { get; set; }
/// <summary>连接名</summary>
[XmlAttribute]
[DisplayName("连接名")]
[Description("连接名")]
public String ConnName { get; set; }
/// <summary>数据库类型</summary>
[XmlAttribute]
[DisplayName("数据库类型")]
[Description("数据库类型")]
public DatabaseType DbType { get; set; }
/// <summary>基类</summary>
[XmlAttribute]
[DisplayName("基类")]
[Description("基类")]
public String BaseType { get; set; }
/// <summary>仅插入的日志型数据</summary>
[XmlAttribute]
[DisplayName("只写")]
[Description("只写")]
public Boolean InsertOnly { get; set; }
#endregion
#region 扩展属性
/// <summary>字段集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
[Category("集合")]
[DisplayName("字段集合")]
[Description("字段集合")]
public List<IDataColumn> Columns { get; private set; }
/// <summary>索引集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
[Category("集合")]
[DisplayName("索引集合")]
[Description("索引集合")]
public List<IDataIndex> Indexes { get; private set; }
/// <summary>主字段。主字段作为业务主要字段,代表当前数据行意义</summary>
[XmlIgnore, IgnoreDataMember]
public IDataColumn Master => Columns.FirstOrDefault(e => e.Master) ?? Columns.FirstOrDefault(e => e.PrimaryKey);
/// <summary>主键集合。可以是空集合,但不能为null。</summary>
[XmlIgnore, IgnoreDataMember]
public IDataColumn[] PrimaryKeys => Columns.FindAll(item => item.PrimaryKey).ToArray();
private String _DisplayName;
/// <summary>显示名</summary>
[XmlAttribute]
[DisplayName("显示名")]
[Description("显示名")]
public String DisplayName
{
get
{
get
{
if (String.IsNullOrEmpty(_DisplayName)) _DisplayName = ModelResolver.Current.GetDisplayName(Name, _Description);
return _DisplayName;
}
//set
//{
// if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
// _DisplayName = value;
// if (String.IsNullOrEmpty(_Description))
// _Description = _DisplayName;
// else if (!_Description.StartsWith(_DisplayName))
// _Description = _DisplayName + "。" + _Description;
//}
if (String.IsNullOrEmpty(_DisplayName)) _DisplayName = ModelResolver.Current.GetDisplayName(Name, _Description);
return _DisplayName;
}
//set
//{
// if (!String.IsNullOrEmpty(value)) value = value.Replace("\r\n", "。").Replace("\r", " ").Replace("\n", " ");
// _DisplayName = value;
// if (String.IsNullOrEmpty(_Description))
// _Description = _DisplayName;
// else if (!_Description.StartsWith(_DisplayName))
// _Description = _DisplayName + "。" + _Description;
//}
}
/// <summary>扩展属性</summary>
[XmlIgnore, IgnoreDataMember]
[Category("扩展")]
[DisplayName("扩展属性")]
[Description("扩展属性")]
public IDictionary<String, String> Properties { get; private set; }
///// <summary>忽略名称大小写</summary>
//[XmlAttribute]
//[DisplayName("是否忽略大小写")]
//[Description("是否忽略大小写")]
//public String IgnoreNameCase { get; set; }
#endregion
#region 构造
/// <summary>初始化</summary>
public XTable()
{
IsView = false;
/// <summary>扩展属性</summary>
[XmlIgnore, IgnoreDataMember]
[Category("扩展")]
[DisplayName("扩展属性")]
[Description("扩展属性")]
public IDictionary<String, String> Properties { get; private set; }
///// <summary>忽略名称大小写</summary>
//[XmlAttribute]
//[DisplayName("是否忽略大小写")]
//[Description("是否忽略大小写")]
//public String IgnoreNameCase { get; set; }
#endregion
#region 构造
/// <summary>初始化</summary>
public XTable()
{
IsView = false;
Columns = new List<IDataColumn>();
Indexes = new List<IDataIndex>();
Columns = new List<IDataColumn>();
Indexes = new List<IDataIndex>();
Properties = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
}
Properties = new NullableDictionary<String, String>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>初始化</summary>
/// <param name="name">名称</param>
public XTable(String name) : this() => TableName = name;
#endregion
/// <summary>初始化</summary>
/// <param name="name">名称</param>
public XTable(String name) : this() => TableName = name;
#endregion
#region 方法
/// <summary>创建字段</summary>
/// <returns></returns>
public virtual IDataColumn CreateColumn() => new XField { Table = this };
#region 方法
/// <summary>创建字段</summary>
/// <returns></returns>
public virtual IDataColumn CreateColumn() => new XField { Table = this };
/// <summary>创建索引</summary>
/// <returns></returns>
public virtual IDataIndex CreateIndex() => new XIndex { Table = this };
/// <summary>创建索引</summary>
/// <returns></returns>
public virtual IDataIndex CreateIndex() => new XIndex { Table = this };
/// <summary>修正数据</summary>
public virtual IDataTable Fix() => ModelResolver.Current.Fix(this);
/// <summary>修正数据</summary>
public virtual IDataTable Fix() => ModelResolver.Current.Fix(this);
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString()
{
if (String.IsNullOrEmpty(DisplayName))
return Name;
else
return $"{Name}({DisplayName})";
}
#endregion
/// <summary>已重载。</summary>
/// <returns></returns>
public override String ToString()
{
if (String.IsNullOrEmpty(DisplayName))
return Name;
else
return $"{Name}({DisplayName})";
}
#endregion
#region 导入导出
/// <summary>导出</summary>
/// <returns></returns>
public String Export() => this.ToXml();
#region 导入导出
/// <summary>导出</summary>
/// <returns></returns>
public String Export() => this.ToXml();
/// <summary>导入</summary>
/// <param name="xml"></param>
/// <returns></returns>
public static XTable Import(String xml)
{
if (String.IsNullOrEmpty(xml)) return null;
/// <summary>导入</summary>
/// <param name="xml"></param>
/// <returns></returns>
public static XTable Import(String xml)
{
if (String.IsNullOrEmpty(xml)) return null;
return xml.ToXmlEntity<XTable>();
}
#endregion
return xml.ToXmlEntity<XTable>();
}
#endregion
#region ICloneable 成员
/// <summary>克隆</summary>
/// <returns></returns>
Object ICloneable.Clone() => Clone();
#region ICloneable 成员
/// <summary>克隆</summary>
/// <returns></returns>
Object ICloneable.Clone() => Clone();
/// <summary>克隆</summary>
/// <returns></returns>
public XTable Clone()
/// <summary>克隆</summary>
/// <returns></returns>
public XTable Clone()
{
var table = base.MemberwiseClone() as XTable;
// 浅表克隆后,集合还是指向旧的,需要重新创建
table.Columns = new List<IDataColumn>();
foreach (var item in Columns)
{
table.Columns.Add(item.Clone(table));
}
table.Indexes = new List<IDataIndex>();
foreach (var item in Indexes)
{
var table = base.MemberwiseClone() as XTable;
// 浅表克隆后,集合还是指向旧的,需要重新创建
table.Columns = new List<IDataColumn>();
foreach (var item in Columns)
{
table.Columns.Add(item.Clone(table));
}
table.Indexes = new List<IDataIndex>();
foreach (var item in Indexes)
{
table.Indexes.Add(item.Clone(table));
}
return table;
table.Indexes.Add(item.Clone(table));
}
#endregion
return table;
}
#endregion
#region IXmlSerializable 成员
/// <summary>获取架构</summary>
/// <returns></returns>
XmlSchema IXmlSerializable.GetSchema() => null;
#region IXmlSerializable 成员
/// <summary>获取架构</summary>
/// <returns></returns>
XmlSchema IXmlSerializable.GetSchema() => null;
/// <summary>读取</summary>
/// <param name="reader"></param>
void IXmlSerializable.ReadXml(XmlReader reader) => ModelHelper.ReadXml(this, reader);
/// <summary>读取</summary>
/// <param name="reader"></param>
void IXmlSerializable.ReadXml(XmlReader reader) => ModelHelper.ReadXml(this, reader);
/// <summary>写入</summary>
/// <param name="writer"></param>
void IXmlSerializable.WriteXml(XmlWriter writer) => ModelHelper.WriteXml(this, writer);
#endregion
}
/// <summary>写入</summary>
/// <param name="writer"></param>
void IXmlSerializable.WriteXml(XmlWriter writer) => ModelHelper.WriteXml(this, writer);
#endregion
}
\ No newline at end of file
......@@ -370,6 +370,15 @@ public class SQLiteTests
md.Invoke("ParseColumns", table, sql);
Assert.Equal(41, table.Columns.Count);
Assert.Equal("Id", table.Columns[0].Name);
Assert.Equal("integer", table.Columns[0].RawType);
Assert.Equal("TenantId", table.Columns[1].Name);
Assert.Equal("int", table.Columns[1].RawType);
Assert.Equal("ConsigneeUserAddress", table.Columns[^1].Name);
Assert.Equal("nvarchar(50)", table.Columns[^1].RawType);
}
[Fact]
......@@ -428,5 +437,14 @@ public class SQLiteTests
md.Invoke("ParseColumns", table, sql);
Assert.Equal(41, table.Columns.Count);
Assert.Equal("Id", table.Columns[0].Name);
Assert.Equal("integer", table.Columns[0].RawType);
Assert.Equal("TenantId", table.Columns[1].Name);
Assert.Equal("int", table.Columns[1].RawType);
Assert.Equal("ConsigneeUserAddress", table.Columns[^1].Name);
Assert.Equal("nvarchar(50)", table.Columns[^1].RawType);
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册