是否可以从Sqlite查询返回动态对象或数据集?

时间:2016-08-23 16:22:36

标签: c# sqlite xamarin sqlite.net

我在Xamarin.Forms申请中使用Sqlite.Net。到目前为止,如果我的对象是这样的类,那么返回对象列表非常棒:

SqliteDatabase.Connection.Query<Customer>("Select * from Customers");

我现在想从查询中动态返回DataSet的等效内容

SqliteDatabase.Connection.Query("Select * from Customers inner join Calls on Customers.Id=Calls.CustomerId")

现在,从第二个查询开始,我想返回一个DataSet而不是一个对象列表。我知道我可以创建一个新对象,它将CustomersCalls的列组合在一起,但我不希望每次要查询数据库时都必须创建对象。

是否可以动态返回DatasetObject

5 个答案:

答案 0 :(得分:2)

SQLite.NET PCL是围绕sqlite的.NET包装器。

因此,您可以通过在LINQ或Lambda中使用连接而不是在Query中查询类似于EF的查询。包装器将为您处理转换为sqlite查询。

然后,您可以返回已连接类型或动态类型的新数据类型。

注意:sqlite(more info)不直接支持联接,并且提到了here

示例代码:

CALL apoc.periodic.commit(
 "MATCH (child:Entity)
  WHERE child.PARENTID > 0 AND NOT ()-[:PARENT_OF]->(child)
  WITH child.PARENTID AS pid, child
  LIMIT {limit}
  MATCH (parent:Entity {ENT_ID : pid})
  CREATE (parent)-[:PARENT_OF]->(child)
  RETURN COUNT(*);",
{limit: 10000});

Lambda版本:

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 };

答案 1 :(得分:1)

最后,我实际设法提出了一个方法,该方法将运行任何查询,并将行作为列表中的项返回,并将列作为数组中的对象返回:

    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 colType = SQLite3.ColumnType(stQuery, i);
                    switch (colType)
                    {
                        case SQLite3.ColType.Blob:
                            obj[i] = SQLite3.ColumnBlob(stQuery, i);
                            break;
                        case SQLite3.ColType.Float:
                            obj[i] = SQLite3.ColumnDouble(stQuery, i);
                            break;
                        case SQLite3.ColType.Integer:
                            obj[i] = SQLite3.ColumnInt(stQuery, i);
                            break;
                        case SQLite3.ColType.Null:
                            obj[i] = null;
                            break;
                        case SQLite3.ColType.Text:
                            obj[i] = SQLite3.ColumnString(stQuery, i);
                            break;
                    }
                }
            }
            return lstRes;
        }
        catch (Exception)
        {
            return null;
        }
        finally
        {
            if (stQuery != null)
            {
                SQLite3.Finalize(stQuery); 
            }
        }
    }

答案 2 :(得分:0)

非常感谢user1!工作完美。 这里只是一个如何使用ur方法的例子:

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]);
    }
}

答案 3 :(得分:0)

听起来你想要做的就是重新创建ADO.NET。当你说&#34; DataSet&#34;时,我猜你在谈论ADO.NET。这可能意味着您不想使用SQLite.Net库中内置的ORM功能。

我创建了这个版本的库,允许您从SQLite数据库中进行平面表读取。这意味着如果您愿意,可以将数据读入ADO.NET数据集。

https://github.com/MelbourneDeveloper/SQLite.Net.Standard

答案 4 :(得分:0)

与@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}")
                    };
                }
            }
        }
    }