Daniel
Daniel

Reputation: 1755

How to get one field value from Sqlite request?

I use this function to make query:

public SQLiteDataReader returnDataReader(string txtQuery)
        {
            SQLiteCommand cmd = new SQLiteCommand();
            try
            {
                cmd.Connection = Openconn();
                cmd.CommandText = txtQuery;
                SQLiteDataReader rd;
                rd = cmd.ExecuteReader();
                return rd;
            }
            catch (Exception Ex)
            {
                throw Ex;
            }
            finally
            {
                cmd = null;
            }
        }

And this is my query:

 SQLiteDataReader data = db.returnDataReader("SELECT created_at FROM Transactions ORDER BY created_at DESC LIMIT 1");

I tried to get value of created_at field from query like as:

string res = data["created_at"].ToString();

It returns me error. Also I have checked this query directly in Sqlite manager. It works and return one row.

Error is:

System.InvalidOperationException occurred HResult=0x80131509
Message=No current row Source=System.Data.SQLite StackTrace: at System.Data.SQLite.SQLiteDataReader.CheckValidRow() at System.Data.SQLite.SQLiteDataReader.GetValue(Int32 i) at System.Data.SQLite.SQLiteDataReader.get_Item(String name) at Ukraine.StatisticService.lastsync() in D:\Projects\c-tests-ukraine\Ukraine\Library\StatisticService.cs:line 25 at Ukraine.Main.Form1_Load(Object sender, EventArgs e) in D:\Projects\c-tests-ukraine\Ukraine\Main.cs:line 81 at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible)
at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Upvotes: 2

Views: 10707

Answers (1)

Steve
Steve

Reputation: 216302

Just calling ExecuteReader is not enough. Initially any kind of DataReader is positioned before any row retrieved. You need to call Read on the reader to position it on the first row returned

SQLiteDataReader data = db.returnDataReader(.....);
if(data.Read())
{
    string res = data["created_at"].ToString();
    ....
}

or add a loop

SQLiteDataReader data = db.returnDataReader(.....);
while(data.Read())
{
     ..get data from your rows here
}

However I don't consider your approach to return a SqlLiteDataReader a good practice. The reader depends on the connection being open and the connections are objects that you should really close as fast as possible to avoid dangerous resources leaks.

I suggest to use another approach to read you data

public void ReadData(string txtQuery, Action<SQLiteDataReader> loader)
{
    using(SQLiteConnection con = Openconn())
    using(SQLiteCommand cmd = new SQLiteCommand(txtQuery, con))
    using(SQLiteDataReader rd = cmd.ExecuteReader())
    {
        while(rd.Read())
            loader(rd);
    }
}

Then you call this method passing the delegate to the method that reads your data

ReadData(...querytext..., readCreatedData);

and then write the method readCreatedData that will be called by the code where you open the connection and the other disposable objects.

void readCreatedData(SQLiteDataReader data)
{
     string res = data["created_at"].ToString();
     .....
}

Finally as Rufo pointed in its comment you are really just reading a single value from a single column and this is better done using a simple ExecuteScalar

public string ReadString(string txtQuery)
{
    using(SQLiteConnection con = Openconn())
    using(SQLiteCommand cmd = new SQLiteCommand(txtQuery, con))
    {
        object result = cmd.ExecuteScalar();
        return (result == null ? "" : result.ToString());
    }
}

Upvotes: 3

Related Questions