是否可以从 Sqlite 查询 return 动态对象或数据集?
Is it possible to return dynamic objects or Dataset from a Sqlite Query?
我在 Xamarin.Forms
应用程序中使用 Sqlite.Net。到目前为止,如果我的对象是 class,它在 returning 对象列表方面做得很好:
SqliteDatabase.Connection.Query<Customer>("Select * from Customers");
我现在想 return 从我的查询中动态地 DataSet
等价物
SqliteDatabase.Connection.Query("Select * from Customers inner join Calls on Customers.Id=Calls.CustomerId")
现在从第二个查询我想 return 一个 DataSet
而不是一个对象列表。我知道我可以创建一个新对象,它结合了 Customers
和 Calls
的列,但我不想每次查询数据库时都必须创建对象。
是否可以动态 return 一个 Dataset
或 Object
?
SQLite.NET PCL 是围绕 sqlite 的 .NET 包装器。
因此,您可以通过在 LINQ 或 Lambda 中使用联接而不是在查询中使用类似于 EF 的查询。包装器将为您处理到 sqlite 查询的转换。
然后您可以 return 连接类型或动态类型的新数据类型。
注意:sqlite不直接支持连接(more info) and work around is mentioned here。
示例代码:
var conn = new SQLiteConnection(sqlitePlatform, "foofoo");
var query = from customer in conn.Table<Customers>().ToList()
join call in conn.Table<Calls>().ToList()
on customer.ID equals call.CustomerId
select new { Customer = customer , Calls = call };
Lambda 版本:
conn.Table<Customer>().ToList().Join
(conn.Table<Call>().ToList(),
customer => customer.Id,
call => call.CustomerId,
(customer, call) => new { Customer = customer, Calls = call });
最后,我实际上想出了一个方法,可以 运行 任何查询,return 行作为列表中的项目,列作为数组中的对象:
public List<object[]> RunSql(string sqlString, bool includeColumnNamesAsFirstRow)
{
var lstRes = new List<object[]>();
SQLitePCL.sqlite3_stmt stQuery = null;
try
{
stQuery = SQLite3.Prepare2(fieldStrikeDatabase.Connection.Handle, sqlString);
var colLenght = SQLite3.ColumnCount(stQuery);
if (includeColumnNamesAsFirstRow)
{
var obj = new object[colLenght];
lstRes.Add(obj);
for (int i = 0; i < colLenght; i++)
{
obj[i] = SQLite3.ColumnName(stQuery, i);
}
}
while (SQLite3.Step(stQuery) == SQLite3.Result.Row)
{
var obj = new object[colLenght];
lstRes.Add(obj);
for (int i = 0; i < colLenght; i++)
{
var columnType = SQLitePCL.raw.sqlite3_column_decltype(stQuery, i);
switch (columnType)
{
case "text":
obj[i] = SQLite3.ColumnString(stQuery, i);
break;
case "int":
obj[i] = SQLite3.ColumnInt(stQuery, i);
break;
case "real":
obj[i] = SQLite3.ColumnDouble(stQuery, i);
break;
case "blob":
obj[i] = SQLite3.ColumnBlob(stQuery, i);
break;
case "null":
obj[i] = null;
break;
}
}
}
return lstRes;
}
catch (Exception)
{
return null;
}
finally
{
if (stQuery != null)
{
SQLite3.Finalize(stQuery);
}
}
}
非常感谢 user1!工作完美。
这只是一个如何使用你的方法的例子:
var objects = mySQLiteConnection.RunSql("SELECT * FROM Persons", true);
// ColumnNames
List<string> ColumnNames = new List<string>();
for (int column = 0; column < objects[0].Length; column++)
{
if (objects[0][column] != null) spaltennamen.Add((string)objects[0][column]);
}
// RowValues
for (int row = 1; row < objects.Count; row++)
{
for (int column = 0; column < objects[row].Length; column++)
{
if (objects[row][column] != null) System.Diagnostics.Debug.WriteLine(spaltennamen[column] + " : " + objects[row][column]);
}
}
听起来您想要做的基本上是重新创建 ADO.NET。当你说 "DataSet" 时,我猜你说的是 ADO.NET。这可能意味着您不想使用 SQLite.Net 库中内置的 ORM 功能。
我已经创建了这个版本的库,它允许您从 SQLite 数据库中进行平面 table 读取。这意味着您可以根据需要将数据读入 ADO.NET 数据集。
与@Fabian Monkemoller 不同,我无法让@User1 的代码立即运行。这是一个修改版本,它使用可空引用类型和方法嵌套将主代码与 try-catch 块分开:
public static object?[][]? ToDataSet(this SQLiteConnection sqlConnection, string query , bool includeColumnNamesAsFirstRow = true)
{
var stQuery = SQLite3.Prepare2(sqlConnection.Handle, query );
var colLength = SQLite3.ColumnCount(stQuery);
try
{
return SelectRows().ToArray();
}
catch (Exception e)
{
return null;
}
finally
{
if (stQuery != null)
{
SQLite3.Finalize(stQuery);
}
}
IEnumerable<object?[]> SelectRows()
{
if (includeColumnNamesAsFirstRow)
{
yield return SelectColumnNames(stQuery, colLength).ToArray();
}
while (SQLite3.Step(stQuery) == SQLite3.Result.Row)
{
yield return SelectColumns(stQuery, colLength).ToArray();
}
static IEnumerable<object> SelectColumnNames(SQLitePCL.sqlite3_stmt stQuery, int colLength)
{
for (int i = 0; i < colLength; i++)
{
yield return SQLite3.ColumnName(stQuery, i);
}
}
static IEnumerable<object?> SelectColumns(SQLitePCL.sqlite3_stmt stQuery, int colLength)
{
for (int i = 0; i < colLength; i++)
{
var x = SQLitePCL.raw.sqlite3_column_decltype(stQuery, i);
yield return x switch
{
"text" => SQLite3.ColumnString(stQuery, i),
"integer" => SQLite3.ColumnInt(stQuery, i),
"bigint" => SQLite3.ColumnInt64(stQuery, i),
"real" => SQLite3.ColumnDouble(stQuery, i),
"blob" => SQLite3.ColumnBlob(stQuery, i),
"null" => null,
_ => throw new Exception($"Unexpected type encountered in for query {stQuery}")
};
}
}
}
}
我在 Xamarin.Forms
应用程序中使用 Sqlite.Net。到目前为止,如果我的对象是 class,它在 returning 对象列表方面做得很好:
SqliteDatabase.Connection.Query<Customer>("Select * from Customers");
我现在想 return 从我的查询中动态地 DataSet
等价物
SqliteDatabase.Connection.Query("Select * from Customers inner join Calls on Customers.Id=Calls.CustomerId")
现在从第二个查询我想 return 一个 DataSet
而不是一个对象列表。我知道我可以创建一个新对象,它结合了 Customers
和 Calls
的列,但我不想每次查询数据库时都必须创建对象。
是否可以动态 return 一个 Dataset
或 Object
?
SQLite.NET PCL 是围绕 sqlite 的 .NET 包装器。
因此,您可以通过在 LINQ 或 Lambda 中使用联接而不是在查询中使用类似于 EF 的查询。包装器将为您处理到 sqlite 查询的转换。
然后您可以 return 连接类型或动态类型的新数据类型。
注意:sqlite不直接支持连接(more info) and work around is mentioned here。
示例代码:
var conn = new SQLiteConnection(sqlitePlatform, "foofoo");
var query = from customer in conn.Table<Customers>().ToList()
join call in conn.Table<Calls>().ToList()
on customer.ID equals call.CustomerId
select new { Customer = customer , Calls = call };
Lambda 版本:
conn.Table<Customer>().ToList().Join
(conn.Table<Call>().ToList(),
customer => customer.Id,
call => call.CustomerId,
(customer, call) => new { Customer = customer, Calls = call });
最后,我实际上想出了一个方法,可以 运行 任何查询,return 行作为列表中的项目,列作为数组中的对象:
public List<object[]> RunSql(string sqlString, bool includeColumnNamesAsFirstRow)
{
var lstRes = new List<object[]>();
SQLitePCL.sqlite3_stmt stQuery = null;
try
{
stQuery = SQLite3.Prepare2(fieldStrikeDatabase.Connection.Handle, sqlString);
var colLenght = SQLite3.ColumnCount(stQuery);
if (includeColumnNamesAsFirstRow)
{
var obj = new object[colLenght];
lstRes.Add(obj);
for (int i = 0; i < colLenght; i++)
{
obj[i] = SQLite3.ColumnName(stQuery, i);
}
}
while (SQLite3.Step(stQuery) == SQLite3.Result.Row)
{
var obj = new object[colLenght];
lstRes.Add(obj);
for (int i = 0; i < colLenght; i++)
{
var columnType = SQLitePCL.raw.sqlite3_column_decltype(stQuery, i);
switch (columnType)
{
case "text":
obj[i] = SQLite3.ColumnString(stQuery, i);
break;
case "int":
obj[i] = SQLite3.ColumnInt(stQuery, i);
break;
case "real":
obj[i] = SQLite3.ColumnDouble(stQuery, i);
break;
case "blob":
obj[i] = SQLite3.ColumnBlob(stQuery, i);
break;
case "null":
obj[i] = null;
break;
}
}
}
return lstRes;
}
catch (Exception)
{
return null;
}
finally
{
if (stQuery != null)
{
SQLite3.Finalize(stQuery);
}
}
}
非常感谢 user1!工作完美。 这只是一个如何使用你的方法的例子:
var objects = mySQLiteConnection.RunSql("SELECT * FROM Persons", true);
// ColumnNames
List<string> ColumnNames = new List<string>();
for (int column = 0; column < objects[0].Length; column++)
{
if (objects[0][column] != null) spaltennamen.Add((string)objects[0][column]);
}
// RowValues
for (int row = 1; row < objects.Count; row++)
{
for (int column = 0; column < objects[row].Length; column++)
{
if (objects[row][column] != null) System.Diagnostics.Debug.WriteLine(spaltennamen[column] + " : " + objects[row][column]);
}
}
听起来您想要做的基本上是重新创建 ADO.NET。当你说 "DataSet" 时,我猜你说的是 ADO.NET。这可能意味着您不想使用 SQLite.Net 库中内置的 ORM 功能。
我已经创建了这个版本的库,它允许您从 SQLite 数据库中进行平面 table 读取。这意味着您可以根据需要将数据读入 ADO.NET 数据集。
与@Fabian Monkemoller 不同,我无法让@User1 的代码立即运行。这是一个修改版本,它使用可空引用类型和方法嵌套将主代码与 try-catch 块分开:
public static object?[][]? ToDataSet(this SQLiteConnection sqlConnection, string query , bool includeColumnNamesAsFirstRow = true)
{
var stQuery = SQLite3.Prepare2(sqlConnection.Handle, query );
var colLength = SQLite3.ColumnCount(stQuery);
try
{
return SelectRows().ToArray();
}
catch (Exception e)
{
return null;
}
finally
{
if (stQuery != null)
{
SQLite3.Finalize(stQuery);
}
}
IEnumerable<object?[]> SelectRows()
{
if (includeColumnNamesAsFirstRow)
{
yield return SelectColumnNames(stQuery, colLength).ToArray();
}
while (SQLite3.Step(stQuery) == SQLite3.Result.Row)
{
yield return SelectColumns(stQuery, colLength).ToArray();
}
static IEnumerable<object> SelectColumnNames(SQLitePCL.sqlite3_stmt stQuery, int colLength)
{
for (int i = 0; i < colLength; i++)
{
yield return SQLite3.ColumnName(stQuery, i);
}
}
static IEnumerable<object?> SelectColumns(SQLitePCL.sqlite3_stmt stQuery, int colLength)
{
for (int i = 0; i < colLength; i++)
{
var x = SQLitePCL.raw.sqlite3_column_decltype(stQuery, i);
yield return x switch
{
"text" => SQLite3.ColumnString(stQuery, i),
"integer" => SQLite3.ColumnInt(stQuery, i),
"bigint" => SQLite3.ColumnInt64(stQuery, i),
"real" => SQLite3.ColumnDouble(stQuery, i),
"blob" => SQLite3.ColumnBlob(stQuery, i),
"null" => null,
_ => throw new Exception($"Unexpected type encountered in for query {stQuery}")
};
}
}
}
}