Можно ли вернуть динамические объекты или набор данных из Sqlite Query?

Я использую Sqlite.Net в моем Xamarin.Forms приложение. До сих пор было здорово возвращать списки объектов, если мой объект - это класс:

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

Теперь я хотел бы вернуть эквивалент DataSet динамически из моего запроса

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

Теперь из второго запроса я хотел бы вернуть DataSet вместо списка объектов. Я знаю, что мог бы создать новый объект, который объединяет столбцы Customers а также Calls но я не хочу создавать объекты каждый раз, когда хочу запросить базу данных.

Можно ли просто динамически вернуть Dataset или же Object?

4 ответа

Решение

В конце концов мне действительно удалось придумать метод, который будет запускать любой запрос и возвращать строки как элементы в списке, а столбцы как объекты в массиве:

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

SQLite.NET PCL - это оболочка.NET для sqlite.

Поэтому вы можете выполнять запросы, аналогичные EF, используя соединение в LINQ или Lambda, а не в Query. Оболочка будет обрабатывать преобразование в sqlite запрос для вас.

Затем вы можете вернуть новый тип данных объединенного или динамического типа.

Примечание. Соединения напрямую не поддерживаются в sqlite ( дополнительная информация), и обойти их можно здесь.

Образец кода:

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

Лямбда-версия:

conn.Table<Customer>().ToList().Join
(conn.Table<Call>().ToList(),
customer => customer.Id,
call => call.CustomerId, 
(customer, call) => new { Customer = customer, Calls = call });

Спасибо большое 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]);
    }
}

В отличие от @Fabian Monkemoller, я не смог заставить работать код @User1 сразу. Это модифицированная версия, в которой используются ссылочные типы, допускающие значение NULL, и вложение методов для отделения основного кода от блока 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}")
                    };
                }
            }
        }
    }

Похоже, что вы хотите воссоздать ADO.NET. Когда вы говорите "DataSet", я предполагаю, что вы говорите об ADO.NET. Это, вероятно, означает, что вы не хотите использовать функциональность ORM, встроенную в библиотеку SQLite.Net.

Я создал эту версию библиотеки, которая позволит вам выполнять чтение плоских таблиц из базы данных SQLite. Это означает, что вы МОЖЕТЕ прочитать данные в набор данных ADO.NET, если хотите.

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

Другие вопросы по тегам