Unexplainable MySQL composite key issue with .NET Application - c#

I am writing a .NET application that interact with MySQL database using ODBC connection. My application will create the database schema and tables on the database upon start up. However, I encountered a weird unexplainable case below:
First my application will create the following table
CREATE TABLE IF NOT EXISTS `sample` (
`item_ID` varchar(20) NOT NULL,
`item_No` int(11) NOT NULL,
`sample_col1` varchar(20) NOT NULL,
`sample_col2` varchar(20) NOT NULL,
PRIMARY KEY (`item_ID`, `item_No`)
) ENGINE=InnoDB;
Populate the table with
INSERT INTO sample SET item_ID='abc', item_No=1, sample_col1='', sample_col2='';
INSERT INTO sample SET item_ID='abc', item_No=2, sample_col1='', sample_col2='';
Then I execute a SELECT query from within the .NET application using the following code:
Dim query As String
query = "SELECT item_ID, item_No, sample_col1, sample_col2 FROM sample"
Dim conn As New OdbcConnection("Driver={MySQL ODBC 5.1 Driver};Server=localhost; port=3306;Database=test; User=dbuser;Password=dbpassword;Option=3;")
Dim cmd As New OdbcDataAdapter(query, conn)
Dim dt As New DataTable
cmd.FillSchema(dt, SchemaType.Source)
cmd.Fill(dt)
conn.Close()
The cmd.Fill(dt) line will throw an Exception: "Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints".
However if I modify the table creation query to:
CREATE TABLE IF NOT EXISTS `sample` (
`item_ID` varchar(20) NOT NULL,
`item_No` int(11) NOT NULL,
`sample_col1` varchar(20) NOT NULL,
`sample_col2` varchar(20) NOT NULL,
PRIMARY KEY (`item_No`,`item_ID`) '--> Here Primary Key order is inverted
) ENGINE=InnoDB;
The vb.net code works perfectly. Notice on the second creation query I inverted the order of the PRIMARY KEY creation. On the first example I put item_ID first while on the second example I put item_No first.
Does anyone has any clue why this is happening? Also is there any difference from the point of view of MySQL database between the first and second create query?
Any input will be appreciated. Thank you !

Related

Insert to SQL Server from table type fails if more than 1 row

The following procedure gets data from C# as a datatable. I am sure that the table is sent with multiple rows. If it does have multiple rows, then no data is inserted, but if the data table contains only one row, it inserts it without any problems.
ALTER PROCEDURE [dbo].[MergeContactInfo]
#ContactInfo dbo.[PersonContactTableType] READONLY
AS
BEGIN
MERGE INTO PersonContact AS pc
USING #ContactInfo AS ci ON pc.Person = ci.Person
WHEN MATCHED THEN
UPDATE SET pc.Value = ci.Value, pc.Type = ci.Type
WHEN NOT MATCHED THEN
INSERT VALUES(ci.Person, ci.Type, ci.Value);
END
Any solution why multiple rows not inserted and only one row is inserted, there's no unique constraints.
#Contact Info is the following
CREATE TYPE [dbo].[PersonContactTableType] AS TABLE(
[Person] [int] NOT NULL,
[Type] [tinyint] NOT NULL,
[Value] [varchar](100) NOT NULL,
PRIMARY KEY CLUSTERED ([Person] ASC) WITH (IGNORE_DUP_KEY = OFF)
)
GO
Check your C# datatable content. Each number in "Person" field must be unique. Procedure perfectly works as designed.
Your code works perfect on SQL side,
I tested playing with the content of the table variable and I see that it is merged with table data as expected
declare #CI as [PersonContactTableType];
insert into #CI values (11,1,'ERALPER'),(12,2,'The Phantom'),(13,2,'Lord Vader'),(14,1,'Kodyaz')
exec [MergeContactInfo] #CI;
go
select * from PersonContact

Failed to insert data through LINQ to SQL server

I'm trying to insert data into the database using LINQ. In me SQL server side I wrote a sequence to generate a custom id with a prefix. Here what I did in my code,
ALLibraryDataClassesDataContext dbContext = new ALLibraryDataClassesDataContext();
dbContext.Books.InsertOnSubmit(book);
dbContext.SubmitChanges();
dbContext.Dispose();
In my book object I'm not setting the BookID because it's generating from the sequence. When I'm executing
INSERT INTO library_db.dbo.Book([BookName]) VALUES ('SH')
This inserts data with the auto generated id. But when I'm running the code, It gives an SQLException,
Cannot insert the value NULL into column 'BookId', table 'library_db.dbo.Book'; column does not allow nulls. INSERT fails.
EDITED
My sequence and table creation,
CREATE TABLE [dbo].[Book] (
[BookId] VARCHAR (50) NOT NULL,
[BookName] VARCHAR (50) NULL,
[AuthorName] VARCHAR (50) NULL,
[PublisherName] VARCHAR (50) NULL,
[PublishedDate] DATE NULL,
[price] MONEY NULL,
[PurchasedDate] DATE NULL,
[PurchasedBillNo] VARCHAR (50) NULL,
[CategoryId] VARCHAR (50) NULL,
[NoOfCopies] VARCHAR (50) NULL,
[FinePerDay] MONEY NULL,
[BookImage] VARCHAR (2000) NULL,
PRIMARY KEY CLUSTERED ([BookId] ASC),
CONSTRAINT [FK_Book_Category] FOREIGN KEY ([CategoryId]) REFERENCES [dbo].
[Category] ([CategoryId])
);
GO
CREATE SEQUENCE dbo.BookId_Seq AS
INT START WITH 1
INCREMENT BY 1 ;
GO
ALTER TABLE dbo.Book
ADD CONSTRAINT Const_BookId_Seq
DEFAULT FORMAT((NEXT VALUE FOR dbo.BookId_Seq),'B0000#') FOR [BookId];
GO
What is the different between running a query manually and through LINQ? Is there a possible way to insert data into code(LINQ) with a custom id?
I'm not sure if you can do this with LINQ-to-SQL, but give it a try:
In the context designer, set "Auto Generated Value" = true for BookId. This tells LINQ-to-SQL to exclude the column from insert statements. Now the database will fall back to the default constraint, which doesn't happen when an insert statement supplies a value.
However, there may be one problem. When auto-generated value is defined for a primary key column, LINQ-to-SQL will try to read the generated value afterwards by a select statement looking like
SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]
Obviously, drawing the value from a sequence will leave SCOPE_IDENTITY() undefined. At best this will prevent you from reading the generated key value from the book variable after SubmitChanges, but in the worst case it will cause an error that you can't work around.

How to make sequential id number in SQL Server start form 1 like in an MS Access database

When I use Microsoft SQL Server database and make a filed's data type as uniqueidentifier and use the function newid() or newsequentialid(), it makes a new id that contain 32 value (hexadecimal value).
However, I need a way to make an auto-increment values starts with number 1 and so on just like auto-increment fields in MS Access.
Then I want to add other values using a C# program while the SQL Server adds the auto-increment field automatically without errors.
Note: I'm using SQL Server 2014, and Visual Studio 2015 perf.
You can use SQL Server method IDENTITY(1,1) to increment a column by 1 and starts from 1.
CREATE TABLE [dbo].[XXX](
[ID] [int] IDENTITY(1,1))
If you want the IncrementId also to be the primary key you can create your table like:
CREATE TABLE [dbo].[SomeTable](
[IncrementId] [int] IDENTITY(1,1) NOT NULL,
[OtherColumn] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_SomeTable] PRIMARY KEY CLUSTERED
(
[IncrementId] ASC
))
You than can insert values to the table like
INSERT INTO dbo.SomeTable (OtherColumn) VALUES ('SomeValue')
And this will give you a new row with an id that is the next in line so to speak
Create a Column and make it an identity column to the table
To create an identity column, you may use the Management Studio or u can write a query.
When Inserting data to the table, provide data to the columns, but not to the column created as identity column.
If you want to have an integer identity, you should use either TINYINT, SMALLINT, INT, or BIGINT column for your primary key. If you need GUID, you should use uniqueidentifier column type. You can't mix and match.
Regarding to the auto increment feature, if you need to insert a value manually, you should inactivate IDENTITY option on the table, insert your unique value, and then activate it again. I'm not really sure if it's a good idea to do this, but this is how it works:
-- Allows you to insert a value into identity column.
SET IDENTITY_INSERT [SchemaName].[TableName] ON;
-- Do you insertion here...
-- Deactivates the identity value insertion.
SET IDENTITY_INSERT [SchemaName].[TableName] OFF;

Insert values in both related tables MySQL

I have two tables:
create table `db_csms`.`tbl_item_requester`
(
`id` int not null,
`item_id` int not null,
`requester_id` int not null,
foreign key(`item_id`) references `db_csms`.`tbl_items`(`item_id`),
foreign key(`requester_id`) references `db_csms`.`tbl_user_details`(`user_id`),
primary key (`id`)
);
create table `db_csms`.`tbl_item_requests`
(
`id` int not null,
`item_requester_id` int not null,
`quantity` int(5) not null default 0,
foreign key(`item_requester_id`) references `db_csms`.`tbl_item_requester`(`id`),
primary key (`id`)
);
tbl_items and tbl_user_details are already populated with values. My problem is when a new row is added into table 1 because the table 2 uses the id of that new row inserted in table 1.
My issues are:
How to get the newly inserted row id of table 1 which is needed for inserting in table 2.
Strategy to solve this issue(my thinking):
Remove auto_increment and then generate a random value (using C# code) and use that value in both tables.
Are there any workaround to this problem? Do i have to change my strategy? Is the Database design incorrect?
Since you're using MySQL as your database, there is the specific function LAST_INSERT_ID()
which only works on the current connection that did the insert.
In case of SQL Server you could write:
Insert .... Values(....); Select Scope_Identity()
and use SqlCommand.ExecuteScalar() that returns the first value of the first row, which would be the ID of newly inserted row. In MySql, you should be able to write last_insert_id() instead of Scope_identity().

C# with SQLite and foreign key

I want to implement a patients data base for our software, and have an issue with the foreign key statement. I am using the latest SQLite DLLs, with C#.
When I try to run below code:
dbConnection = "Data Source=SQLiteMyDatabase.db;foreign keys=true;";
if (connections == 0)
{
cnn = new SQLiteConnection(dbConnection);
cnn.Open();
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS patients ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name VARCHAR(100) NOT NULL;");
this.ExecuteNonQuery("CREATE TABLE IF NOT EXISTS images ( FOREIGN KEY (patientID) REFERENCES patients(id), nameRed VARCHAR(20) NOT NULL PRIMARY KEY;");
}
I get the error:
SQLite error near "FOREIGN": syntax error
Why does this happen?
In order to create a foreign key, you must first create the column:
CREATE TABLE IF NOT EXISTS images (
nameRed VARCHAR(20) NOT NULL PRIMARY KEY,
patientID INT,
FOREIGN KEY (patientID) REFERENCES patients(id)
);
Please note:
I moved the primary key column (nameRed) first in the list of columns created, but that's just convention. It could go second.
You use the data type VARCHAR and SQlite will accept that, but be aware that it gets mapped to type TEXT, the maximum length will be ignored, and you will be able to store other data types in the column. SQLite is a bit funny when it comes to data types (it has a very well thought-out system but it's quite different from most other SQL databases).
To make things more confusing, you are allowed to declare the PRIMARY KEY as a property of the column (although you can also do it after the list of columns as with the FOREIGN KEY).

Categories

Resources