SqliteCommand.ExecuteReader() returning no rows - c#

I'm trying to read data from a table in my Sqlite database using the Microsoft.Data.Sqlite classes in a UWP application.
There's a single row in the table, inserted by the same application. I can see the data using a Sqlite database browser, and can copy-paste the SQL query into the database browser, run it, and see the correct result returned.
However, when I run the same query using the code below, no data is returned.
string _query = "SELECT [Source] FROM [Sessions] ORDER BY [MinTimeOffset];";
_SessionList = new List<string>();
using (SqliteCommand _command = new SqliteCommand(_query, _Connection))
{
using (SqliteDataReader _reader = _command.ExecuteReader())
{
while (_reader.Read())
{
_SessionList.Add((string)_reader["Source"]);
}
}
}
The table structure is as follows:
CREATE TABLE Sessions (
[Id] INTEGER PRIMARY KEY AUTOINCREMENT,
[Source] NVARCHAR(255) NOT NULL,
[MinValue] FLOAT NULL,
[MaxValue] FLOAT NULL,
[MinTimeOffset] BIGINT NULL,
[MaxTimeOffset] BIGINT NULL
)
And the data is:
1, "2017-09-17-070007-ELEMNT BOLT BDA2-15-0.fit", NULL, NULL, NULL, NULL
No exceptions are thrown, _reader.Read() returns false the first time it is called, and _reader.HasRows is false, suggesting no data is returned by the query.
I'm sure there's something simple I'm missing here - what could cause this?
Update following comments:
I can use ExecuteScalar() to retrieve data from the same table without a problem, although this is performed as part of a transaction alongside thousands of inserts, so I guess is slightly different. The code for that, which works, is as follows:
_query = "SELECT [Id] FROM Sessions WHERE [Source] = #sessionName LIMIT 1;";
long _sessionId;
_IngestCommand.CommandText = _query;
_IngestCommand.Parameters.Add(new SqliteParameter("#sessionName", sessionName));
_sessionId = (long)_IngestCommand.ExecuteScalar();
Regarding how I connection, the database is either a new database created from scratch via DDL statements, or an existing version created in the same manner. It makes no difference which of those two methods I use. There's only one database file at any time - I'm deleting the folder contents manually before running to be sure I'm not opening any copies or old versions etc, then creating the database programmatically and inserting a bunch of data into it in a transaction, including a record into this table which is successfully retrieved as part of the insert logic, then committing the transaction.
At this point I can browse all of the inserted data in a Sqlite database browser. Then I'm calling the method which includes the ExecuteReader() code shown above and receiving no results. The same connection is used throughout - it's opened in a class constructor and closed in the Dispose() method of that class (I know that's not great design - I'm going to refactor it once I've got this figured out. The connection code is shown below:
var _connSB = new SqliteConnectionStringBuilder
{
Cache = SqliteCacheMode.Private,
DataSource = filename,
Mode = SqliteOpenMode.ReadWriteCreate
};
_Connection = new SqliteConnection(_connSB.ToString());
_Connection.Open();
And the code that builds the database:
string[] _commands = {
"CREATE TABLE IF NOT EXISTS ProjectMetaData ([Id] INTEGER PRIMARY KEY AUTOINCREMENT, [Name] NVARCHAR(100) NOT NULL, [Value] NVARCHAR(255) NOT NULL)",
"CREATE TABLE IF NOT EXISTS Series ([Id] INTEGER PRIMARY KEY AUTOINCREMENT, [Name] NVARCHAR(100) NOT NULL, [Unit] NVARCHAR(48) NOT NULL, [MinValue] FLOAT NULL, [MaxValue] FLOAT NULL, [MinTimeOffset] BIGINT NULL, [MaxTimeOffset] BIGINT FLOAT NULL)",
"CREATE TABLE IF NOT EXISTS Sessions ([Id] INTEGER PRIMARY KEY AUTOINCREMENT, [Source] NVARCHAR(255) NOT NULL, [MinValue] FLOAT NULL, [MaxValue] FLOAT NULL, [MinTimeOffset] BIGINT NULL, [MaxTimeOffset] BIGINT NULL)",
"CREATE TABLE IF NOT EXISTS Data ([Id] INTEGER PRIMARY KEY AUTOINCREMENT, [SeriesId] INT NOT NULL, [SessionId] NOT NULL, [TimeOffset] BIGINT NOT NULL, [Value] FLOAT NOT NULL, [Discounted] BIT NULL)"
};
foreach (string _command in _commands)
{
using (SqliteCommand _dbCommand = new SqliteCommand(_command, _Connection))
{
_dbCommand.ExecuteNonQuery();
}
}

Related

Problem with Database - Foreign Key always Null (T-SQL)

My problem might be a bit long to describe as the project we are working on is a bit bigger, but i will try to be as precise as i can.
Basically we're developing a web-bases woundmanagement (part of a project for university) where the user can enter wounds and set additional information like size, consistence, upload a picture, choose the location, ... .
All those information should be stored in a database (we're working with MS SQL Studio and Visual Studio 2017) where the user can also retrieve it later to view it on the module.
The problem we are facing now is that if we want to show a wound to a special wound to the user, we can't get the foreign keys to work.
We can filter via the casenumber (which is working) but we can't filter wound information by the ID of the wound (each wound is getting an unique ID) - so if we choose a wound, we still get information about ALL wounds which are stored for the given casenr.
This is our "main-table" where each wound is getting an unique ID which is also an ascending identity column:
[wound_id] INT IDENTITY (1, 1) NOT NULL,
[wound_type] VARCHAR (500) NULL,
[wound_description] VARCHAR (500) NULL,
[decuGrade] INT NULL,
[wound_comments] VARCHAR (500) NULL,
[wound_timeReal] DATETIME NULL,
[wound_timeGiven] DATETIME NULL,
[casenumber] INT NULL,
[username] VARCHAR (50) NULL,
PRIMARY KEY CLUSTERED ([wound_id] ASC)
);
If the user enters the information and clicks "Next", a function is called in code behind which fills the table:
_db.SaveWoundDetails(casenr, woundValue, decu, additional_info, realTime, givenBackDocDate, user);
This leads to our database-class, where we have our queries for the database, in this case:
public void SaveWoundDetails(int casenr, string woundType, int decuGrade, string woundComment, DateTime timeReal, DateTime timeGiven , string user)
{
var table = ConfigurationManager.AppSettings["woundDetailsTable"];
var insertQuery = "INSERT INTO " + table + "(casenumber, wound_type, decuGrade, wound_comments, wound_timeReal, wound_timeGiven, username) VALUES (#casenr, #woundType, #decuGrade, #woundComment, #timeReal, #timeGiven, #user)";
var cmd = new SqlCommand(insertQuery);
cmd.Parameters.AddWithValue("#casenr", casenr);
cmd.Parameters.AddWithValue("#woundType", woundType);
cmd.Parameters.AddWithValue("#decuGrade", decuGrade);
cmd.Parameters.AddWithValue("#woundComment", woundComment);
cmd.Parameters.AddWithValue("#timeReal", timeReal);
cmd.Parameters.AddWithValue("#timeGiven", timeGiven);
cmd.Parameters.AddWithValue("#user", user);
var db = DatabaseController.getDataBaseController();
try
{
var sqlcmd = db.executeSQL(cmd);
}
catch (SqlException e)
{
}
}
The connection etc. is in a Database-handler class which is not relevant at the moment.
Until here it works fine. But now we have a second table for more information about the wound, which is also filled on next click, related to this table:
CREATE TABLE [dbo].[epadoc_mod_wound_progress] (
[progress_id] INT IDENTITY (1, 1) NOT NULL,
[wound_length] INT NULL,
[wound_width] INT NULL,
[wound_depth] INT NULL,
[wound_surrounding] VARCHAR (500) NULL,
[wound_consistence] VARCHAR (500) NULL,
[wound_state] VARCHAR (200) NULL,
[wound_painscale] VARCHAR (MAX) NULL,
[wound_itch] VARCHAR (MAX) NULL,
PRIMARY KEY CLUSTERED ([progress_id] ASC)
With the INSERT-METHOD:
public void SaveWoundProgress(int woundLength, int woundWidth, int woundDepth, string woundSurrounding, string woundConsistence, string woundState, string woundPainScale, string woundItch)
{
var table = ConfigurationManager.AppSettings["woundProgressTable"];
var insertQuery = "INSERT INTO " + table + "(wound_length,wound_width,wound_depth, wound_surrounding, wound_consistence, wound_state, wound_painscale, wound_itch) VALUES (#woundLength, #woundWidth, #woundDepth, #woundSurrounding, #woundConsistence, #woundState, #woundPainScale, #woundItch)";
var cmd = new SqlCommand(insertQuery);
cmd.Parameters.AddWithValue("#woundLength", woundLength);
cmd.Parameters.AddWithValue("#woundWidth", woundWidth);
cmd.Parameters.AddWithValue("#woundDepth", woundDepth);
cmd.Parameters.AddWithValue("#woundSurrounding", woundSurrounding);
cmd.Parameters.AddWithValue("#woundConsistence", woundConsistence);
cmd.Parameters.AddWithValue("#woundState", woundState);
cmd.Parameters.AddWithValue("#woundPainScale", woundPainScale);
cmd.Parameters.AddWithValue("#woundItch", woundItch);
var db = DatabaseController.getDataBaseController();
try
{
var sqlcmd = db.executeSQL(cmd);
}
catch (SqlException e)
{
}
}
And the method
_db.SaveWoundProgress(wound_length, wound_width, wound_depth, woundArea, woundEdge, woundStatus, painStatus, itchStatus);
which is execute right after the method mentioned above.
I know how to create foreign keys between two tables, but everything we tried failed - if we try to execute it with a foreign key set which is NOT NULL, we're getting a null-exception.
Example of what we tried:
CONSTRAINT [FK_epadoc_mod_wound_details] FOREIGN KEY ([wound_id])
REFERENCES [dbo].[epadoc_mod_wound_progress] ([progress_id])
If we set a foreign key like this, it didn't work.
We came to the conclusion that it must be a problem the callstack when the two methods are executed - but we don't know how we can fix it.
Maybe we have to set the foreign key in the INSERT-query as an explicit variable?
What we want to achieve is that the wound_id of the details-table is taken as foreign key the the progress-table so that a wound can be later changed (for example if it heals the user could re-enter the new size etc.) and we can filter by ID to just show ONE wound to the patient and not all wounds at the same time if clicked on a specific wound.
Sadly i'm not the big database expert so i hope that you can follow my explanations :).
Thanks for any help!
Your epadoc_mod_wound_progress needs to include a [wound_id] INT NOT NULL column. This is what your foreign key should be built on so that one wound can have many wound progresses. Then, in your insert statement, you'll insert the wound_id that generates in woundDetail table insert into epadoc_mod_wound_progress.
Tried to add a comment but I don't have 50 reputation.
I assume from what I can see that you are trying to achieve a one to many relationship between the "main table" and the "epadoc_mod_wound_progress" table, is that right ?
If so, you don't seem to have a field in the "epadoc_mod_wound_progress" table that stores the wound_id, how are you trying to create a foreign key if you are not storing the wound_id ?
Suggest the Primary Key of the epadoc_mod_wound_progress table is a concatenated key of wound_id and progress_id, with wound_id also being the foreign key linking to the main table.
In table epadoc_mod_wound_progress there must be a wound_id INT NOT NULL column acting as foreign key.
Also the constraint must be added to the foreign key table, i.e. the table on the n side of the 1 to n relation. Assuming that the name of the main table is epadoc_mod_wound_details (you did not show it):
ALTER TABLE dbo.epadoc_mod_wound_progress
ADD CONSTRAINT FK_progress_details FOREIGN KEY (wound_id)
REFERENCES dbo.epadoc_mod_wound_details (wound_id)
ON DELETE CASCADE
Also, by adding ON DELETE CASCADE the progress of a wound detail will automatically be deleted when you delete the wound detail.

Entity Framework, cannot add new object without specifying primary key

I am trying to use Identity to make the tables autoincrement the key upon insert. It worked nicely when I used a simple SQL query to insert a value.
CREATE TABLE [dbo].[extrak]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[kategorianev] VARCHAR(50) NULL,
[nev] VARCHAR(50) NULL,
[ar] INT NULL,
[szin] VARCHAR(50) NULL,
[tobbszor_hasznalhato] TINYINT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
However when I use C# code to add a value, I get an exception saying that I should set identity_insert on (I suppose this is when I want to specify a primary key, but I might have missed something). I tried setting It on also, but didn't work (right before calling the add method).
extrak extra = new extrak();
extra.kategorianev = categoryname;
extra.nev = name;
extra.ar = price;
extra.szin = color;
extra.tobbszor_hasznalhato = b;
Console.WriteLine("1");
DataBaseHandler.AddNewExtra(extra);
Console.WriteLine("2");
DataBaseHandler.SaveDB();
The exception happens on saving. Do I have to find the new primary key for myself, and insert that way? Or can I make Entity Framework handle It somehow?
My mate got It. I had to update the model in VS to make It work.
After that the code above worked nicely.

insert and update sql statement in single sql statement

I want to create insert and update sql statements in single statement. But insert statement is for one table and update statement for another table...
this is Appliance_Location table
CREATE TABLE [dbo].[Appliance_Location] (
[Appliance_Id] NCHAR (10) NOT NULL,
[RoomId] NVARCHAR (20) NOT NULL,
[ApplianceName] NCHAR (10) NOT NULL,
[AddDate] DATE NULL,
CONSTRAINT [PK_Appliance_Location] PRIMARY KEY CLUSTERED ([Appliance_Id] ASC)
);
and this is Appliance_Count table
CREATE TABLE [dbo].[Appliance_Count] (
[RoomId] NVARCHAR (20) NOT NULL,`enter code here`
[Bulb] INT NOT NULL,
[Fan] INT NOT NULL,
[AC] INT NOT NULL,
[Computer] INT NOT NULL,
CONSTRAINT [PK_Appliance_Count] PRIMARY KEY CLUSTERED ([RoomId] ASC)
);
when I insert an appliance to the Appliance_Location table then count of that particular appliance in Appliance_Count table should be updated
It is not possible to insert and update in single query. But You have one option for this task. You can create trigger to inserting of one table. And trigger through update value in other table.
Not sure how about other SQL servers, but you are allowed to execute multiple queries using the same syntax in MS SQL.
using (SqlConnection connection = CreateConnection())
{
SqlCommand command = connection.CreateCommand();
command.CommandText = #"INSERT INTO `TableA` VALUES (1, 2, 3);
UPDATE `TableB` SET [Val] = 'value' WHERE [Id] > 10";
command.CommandType = CommandType.Text;
// ... other initializations
return command.ExecuteNonQuery();
}
You even can return values:
INSERT INTO `TableC` VALUES (1, 'value');
SELECT SCOPE_IDENTITY() AS Id;
After this query you can get SQL reader and read "Id" value from the response.
Why don't you just try before asking?

Insert a record in table fails everytime

I have a database connection where i insert data into the table having 2 columns i.e. id,first_name,last_name.
Following is the code:
private void Insert_Click(object sender, EventArgs e)
{
try
{
String query = "INSERT INTO data_table (first_name,last_name) VALUES (#f_name,#l_name)";
using (SqlConnection connection1 = new SqlConnection(
Properties.Settings.Default.DatabaseConnection))
using (SqlCommand insertCommand = new SqlCommand(query, connection1))
{
//a shorter syntax to adding parameters
// insertCommand.Parameters.Add("#id", SqlDbType.Int).Value = 1;
insertCommand.Parameters.Add("#f_name", SqlDbType.NChar).Value = "JAVED";
insertCommand.Parameters.Add("#l_name", SqlDbType.NChar).Value = "GHAMJN";
//make sure you open and close(after executing) the connection
connection1.Open();
insertCommand.ExecuteNonQuery();
connection1.Close();
MessageBox.Show("Record inserted. Please check your table data. :)");
}
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
Following is T-SQL script:
CREATE TABLE [dbo].[data_table] (
[Id] INT NOT NULL IDENTITY,
[first_name] NCHAR (10) NULL,
[last_name] NCHAR (10) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
The issue is created by id: I have set it auto-increment.
When i click insert button a MessageBox pops saying:
Cannot insert the value NULL into column 'Id',table 'C:\Users.......\Database1.MDF.dbo.data_table;column doesn't allows null.INSERT fails
Add identity seed and increment values to your table...
CREATE TABLE [dbo].[data_table] (
[Id] INT NOT NULL IDENTITY(1,1),
[first_name] NCHAR (10) NULL,
[last_name] NCHAR (10) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
Your Id field should be modified as shown below
Deleting that table alongwith all the old copies of old table and creating a new table with suggested Identity(1,1) resolved the issue
try this. The behaviour of Identity Columns can be selectively enabled or disabled with this statement.
If your Identity Column is configured correctly, then this is the only logical explanation for it not behaving as expected
SET IDENTITY_INSERT [dbo].[data_table] ON;
However, it is more likely that your assertion of correctness is flawed and you have not configured the Identity Column correctly.

SQLite: Insert Into Identity Column [duplicate]

This question already has answers here:
Is there AUTO INCREMENT in SQLite?
(9 answers)
Closed last month.
I'm new to SQLite and I'm trying to run the following code:
using (var cn = new SQLiteConnection("Data Source=:memory:;Version=3;")) {
cn.Open();
var cmd = cn.CreateCommand();
cmd.CommandText = "CREATE TABLE [ContentItems] ([Id] [int] IDENTITY(1,1) NOT NULL, [Title] [nvarchar](100) NOT NULL, CONSTRAINT [PK_ContentItems] PRIMARY KEY ([Id]))";
cmd.ExecuteNonQuery();
var cmd2 = cn.CreateCommand();
cmd2.CommandText = "INSERT INTO [ContentItems] (Title) VALUES ('Test 1')";
cmd2.ExecuteNonQuery();
}
But this gives the error:
Abort due to constraint violation ContentItems.Id may not be NULL
I've had a look through the documentation but based on my past SQL experience I cannot see why this doesn't work. I'd appreciate the help. Thanks
SQLite creates what you're thinking of as an IDENTITY column using the AUTOINCREMENT keyword. In your example, the ID column is not created with AUTOINCREMENT and, since it is declared NOT NULL, you must supply a value.
The CREATE statement you're after is:
CREATE TABLE [ContentItems] (
[Id] INTEGER AUTOINCREMENT NOT NULL,
[Title] TEXT NOT NULL,
CONSTRAINT [PK_ContentItems] PRIMARY KEY ([Id])
)
Note that SQLite uses the TEXT data type (although it will map anything containing "CHAR" to that datatype) and doesn't need or respect maximum field lengths.

Categories