So I have this:
INSERT INTO Track (Trackname, Trackinfo) VALUES (Value1, Value2)
INSERT INTO Artiest (Artist) VALUES (Value1)
Both of these tables have an ID that is auto_increment
how can I create a table that will have both the IDs??
I am trying to do this in C#
EDIT: Maybe there is a way in MySQL where I can get the last IDs of the 2 tables?
You either write a stored procedure using T-SQL and SCOPE_IDENTITY().
Or you use LINQ to Entities and retrieve the ID of the newly created Entity.
T-SQL:
DECLARE #TrackID AS int
INSERT INTO Track (Trackname, Trackinfo) VALUES (Value1, Value2)
SET #TrackID = SCOPE_IDENTITY()
DECLARE #ArtiestID AS int
INSERT INTO Artiest (Artist) VALUES (Value1)
SET #ArtiestID = SCOPE_IDENTITY()
Now use those ID's to Insert into your table.
INSERT INTO TrackArtiest (TrackID , ArtiestID ) VALUES (#TrackID , #ArtiestID)
When using Linq to Entities:
var myTrackObject = new Track(Value1, Value2);
var myArtiestObject= new Artiest(Value1);
// db is your datacontext
db.Tracks.Insert(myTrackObject);
db.Artiests.Insert(myArtiestObject);
db.SubmitChanges();
// You can retrieve the id from the object
int trackID = myTrackObject.ID;
int artiestID = myArtiestObject.ID;
var myTrackArtiest = new TrackArtiest(trackID, artiestID);
db.TrackArtiest.Insert(myTrackArtiest );
db.SubmitChanges();
Is this what you meant ?
If you are using SQL and want to return the ID of the insert operation. Use: SCOPE_IDENTITY() function in SQL. But you have to return it and map it to C#
Related
I have a table which generates its primary key from a sequence (that just counts up from 0):
CREATE TABLE [dbo].[testTable](
[id] [int] NOT NULL,
[a] [int] NOT NULL,
CONSTRAINT [PK_testTable] PRIMARY KEY CLUSTERED ([id] ASC))
ALTER TABLE [dbo].[tblTestTable] ADD CONSTRAINT [DF_tblTestTable_id] DEFAULT (NEXT VALUE FOR [seq_PK_tblTestTable]) FOR [id]
I've used Visual Studio's O/R Designer to create the mapping files for the table; the id field is defined as:
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_id", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int id {…}
and now I'm trying to insert data via LINQ.
var testTableRecord = new testTable()
{
a = 1,
};
db.Connection.Open();
db.testTables.InsertOnSubmit(testTableRecord);
db.SubmitChanges();
Console.WriteLine($"id: {testTableRecord.id}");
The problem I'm encountering is, that LINQ seems unable to handle the id generation via sequence as it sets the id implicitly to 0 when inserting.
When I set the id to CanBeNull, the insert fails because it tries to insert NULL into a non-nullable field.
When I set the id to IsDbGenerated, the insert works but it expects an IDENTITY field and tries to load the generated id with SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]',N'#p0 int',#p0=1 and than sets the id in the object to null because SCOPE_IDENTITY() returns null…
I've been thinking about just using IsDbGenerated, destroying the LINQ object and querying the DB for the id, but I don't have anything unique to search for.
Unfortunately changing the id creation mechanism to IDENTITY is not an option.
Do I have to explicitly query the DB for the next sequence value and set the id manually?
Whats the best way to handle these inserts via LINQ?
PS: I need the id because I have to insert more data that uses the id as FK.
Looking at solutions from the raw sql perspective:
1.
INSERT INTO [dbo].[testTable] VALUES (NEXT VALUE FOR [dbo].[seq_PK_tblTestTable], 1)
Simply can't be done in LINQ to SQL as far as I can tell
2.
INSERT INTO [dbo].[testTable] (a) VALUES (1)
This can be achieved in LINQ to SQL by excluding the id property from the testTable entity.
If you need to retrieve ids from the table, you could create separate entities for inserting and querying:
public class testTableInsert {
[ColumnAttribute(...)]
public int a
}
public class testTableResult {
[ColumnAttribute(...)]
public int id
[ColumnAttribute(...)]
public int a
}
3.
DECLARE #nextId INT;
SELECT #nextId = NEXT VALUE FOR [dbo].[seq_PK_tblTestTable];
INSERT INTO [dbo].[testTable] VALUES (#nextId, 1)
As you mentioned, this can be essentially achieved by manually requesting the next id before each insert. If you go this route there are multiple ways to achieve it in your code, you can consider stored procedures or use the LINQ data context to manually execute the sql to retrieve the next sequence value.
Here's a code sample demonstrating how to extend the generated DataContext using partial methods.
public partial class MyDataContext : System.Data.Linq.DataContext
{
partial void InsertTestTable(TestTable instance)
{
using (var cmd = Connection.CreateCommand())
{
cmd.CommandText = "SELECT NEXT VALUE FOR [dbo].[seq_PK_TestTable] as NextId";
cmd.Transaction = Transaction;
int nextId = (int) cmd.ExecuteScalar();
instance.id = nextId;
ExecuteDynamicInsert(instance);
}
}
}
Once the above is implemented, you can safely insert entities like this, and they will generate the correct sequence id.
TestTable entity = new TestTable { a = 2 };
dataContext.TestTables.InsertOnSubmit(entity);
dataContext.SubmitChanges();
Your only hope is a pretty profound refactoring and use a stored procedure to insert records. The stored procedure can be mapped to the class's Insert method in the data context designer.
Using your table definition, the stored is nothing but this:
CREATE PROCEDURE InsertTestTable
(
#id int OUTPUT,
#a AS int
)
AS
BEGIN
INSERT dbo.testTable (a) VALUES (#a);
SET #id = (SELECT CONVERT(int, current_value)
FROM sys.sequences WHERE name = 'seq_PK_tblTestTable')
END
You can import this stored procedure into the context by dragging it from the Sql Object Explorer onto the designer surface, which will then look like this:
The next step is to click the testTable class and click the ellipses button for the Insert method (which got enabled by adding the stored procedure to the context):
And customize it as follows:
That's all. Now LINQ-to-SQL will generate a stored procedure call to insert a record, for example:
declare #p3 int
set #p3=8
declare #p5 int
set #p5=0
exec sp_executesql N'EXEC #RETURN_VALUE = [dbo].[InsertTestTable] #id = #p0 OUTPUT,
#a = #p1',N'#p0 int output,#p1 int,#RETURN_VALUE int output',
#p0=#p3 output,#p1=123,#RETURN_VALUE=#p5 output
select #p3, #p5
Of course you may have to wonder how long you're going to hang on to LINQ-to-SQL. Entity Framework Core has sequence support out of the box. And much more.
I want to enter unique index value into my database when insert other table data. In this case my table index column ID is unique but not auto-increment.
I also want to check the maximum of index value in target table. If the table is empty then index value starts from 0, OR if it contains 1 row then the index value starts from 2.
Already I can successfully do this operation using a stored procedure. But I want to do this operation using Entity Framework when saving data.
My stored procedure is:
ALTER PROCEDURE [dbo].[CreatePerson]
#Name Nvarchar(50),
#Code Nvarchar(50)
AS
BEGIN
Declare #Id int
SET #Id = ISNULL(((SELECT MAX([id]) FROM dbo.tbl_Person)+1),'1')
Insert Into dbo.tbl_Person([Id], [Name], [Code])
Values (#id, #Name, #Code)
END
Can anyone tell me what the LINQ Command for this index value save process?
A straight translation of your SQL stored procedure into Linq would basically be something like this:
var newId = ctx.Persons.Any() ? ctx.Persons.Select(p => p.Id).Max() + 1 : 1;
var newPerson = new Person { Id = newId, Name = someName, Code = someCode };
ctx.Persons.Add(newPerson);
ctx.SaveChanges();
Note: this solution is certainly NOT recommended for inserting unique id's in a database, consider carefully the suggestions of Sharped and Magnus in the comments below the question to better use auto-increment or random guids to solve your problem.
With an auto-incremented id column your code would look like this:
var newPerson = new Person { Name = someName, Code = someCode };
ctx.Persons.Add(newPerson);
ctx.SaveChanges();
var newId = newPerson.Id;
Note that EF will update the id column of the newly created entity for you in code automagically.
How do I execute a query using LINQ to SQL? a query that something goes like this.
Let's say I have this table
CREATE TABLE dbo.Students
(
StudentID INT IDENTITY(1,1) PRIMARY KEY,
Name SYSNAME
);
CREATE TABLE dbo.StudentLoans
(
LoanID INT IDENTITY(1,1) PRIMARY KEY,
StudentID INT FOREIGN KEY REFERENCES dbo.Students(StudentID),
Amount BIGINT -- just being funny
);
Then I wanted to execute this query.
DECLARE
#Name SYSNAME = N'user962206',
#LoanAmount BIGINT = 50000,
#StudentID INT;
INSERT dbo.Students(Name)
SELECT #Name;
SELECT #StudentID = SCOPE_IDENTITY();
INSERT dbo.StudentLoans(StudentID, Amount)
SELECT #StudentID, #LoanAmount;
Is that possible? even if your Rows and Columns are mapped? how can I execute that query with LINQ to SQL ?
It's been a while, but wouldn't it be something like this?
Assuming you've dragged all your tables onto the Linq2Sql designer, simply create a Student object, add a StudentLoan to its StudentLoans collection, and add the Student to the Context.Students collection with myContextInstance.Students.InsertOnSubmit(newStudent) and write out the changes with a call to myContextInstance.SubmitChanges.
So, putting it all together:
using(var myContextInstance=new YourContext())
{
var student = new Student(){Name = "user962206"};
var studentLoan = new StudentLoan(){Amount = 50000};
student.StudentLoans.Add(studentLoan);
myContextInstance.Students.InsertOnSubmit(student);
myContextInstance.SubmitChanges();
}
The code snippet works if your DataContext looks like this:
This is the result of just dragging your tables to the design surface of the dbml file.
If by your question you mean "how do a execute a raw SQL query with LINQ to SQL," then look at the ExecuteCommand and ExecuteQuery methods:
ExecuteCommand -
http://msdn.microsoft.com/en-us/library/system.data.linq.datacontext.executecommand.aspx
ExecuteQuery (Overload 1) - http://msdn.microsoft.com/en-us/library/bb534292.aspx
ExecuteQuery (Overload 2) - http://msdn.microsoft.com/en-us/library/bb361109.aspx
All these methods take a raw SQL query, like yours, and runs it against the database
If you meant by your question "how do I write this SQL query as a LINQ query" then please clarify your question.
I am reading data from csv file and adding data in database. At time of inserting data into database I want to update data with same primary key.
e.g.) I am using two Columns Bar-codes (PK) and Quantity. So, when I insert data from csv file similar barcode quantity will get added.
Can anyone help me? I am using C#.NET and SQL.
Thanks,
Rushabh Shah.
check out the merge keyword. it should do pretty much waht you're asking for.
here's a stored proc that should do it for you.
CREATE PROCEDURE dbo.InsertBarcodeData
#Barcode varchar(255),
#Quantity int
AS
BEGIN
SET NOCOUNT ON;
MERGE myTableName AS target
USING (SELECT #Barcode, #Quantity) AS source (BarCode, Quantity)
ON (target.Barcode= source.Barcode)
WHEN MATCHED THEN
UPDATE SET Quantity = source.Quantity + target.Quantity
WHEN NOT MATCHED THEN
INSERT (BarCode, Quantity)
VALUES (source.BarCode, source.Quantity)
END;
GO
create procedure InsertOrUpdateSales
(
#bar_code nvarchar(100),
#quantity int
)
as
if exists (select * from sales where bar_code = #bar_code)
update sales set quantity = quantity + #quantity where bar_code = #bar_code
else
insert into sales ( bar_code, quantity) values ( #bar_code, #quantity )
go
And
public static void InsertOrUpdateSales(string connection, string barCode, int quantity)
{
using(SqlConnection conn = new SqlConnection(connection))
{
using(SqlCommand comm = new SqlCommand("InsertOrUpdateSales", conn))
{
comm.CommandType = CommandType.StoredProcedure;
comm.Paramters.AddWithValue("#bar_code", barCode);
comm.Paramters.AddWithValue("#quantity", quantity);
comm.ExecuteNonQuery();
}
}
}
Alternatively, if you want to use the merge statement (as #Chris Lively and #nathan gonzalez mentioned) you could get really fancy and do it like this:
BULK INSERT the data from the CSV file to an empty temp table.
MERGE the temp table with the existing table.
TRUNCATE the temp table.
This might give you the best results. (For certain values of "best".)
If you can assume that there is already an existing entry for all of the bar codes in the table you could do this with a Stored procedure with two incominig parameters (#BarCodeID and #AdditionalQuantity)
UPDATE yourTable SET Quantity = Quantity + #AdditionalQuantity WHERE BarCode = #BarCodeID
You can add a Trigger to the table. When ever something is inserted in the table, you can have it run a stored procedure.
I am currently working in C#, and I need to insert a new record into one table, get the new primary key value, and then use that as a foreign key reference in inserting several more records. The Database is MS SQL Server 2003. All help is appreciated!
The way to get the identity of the inserted row is with the SCOPE_IDENTITY() function. If you're using stored procedures then this would look something like the following to return the row identity as an output parameter.
CREATE PROCEDURE dbo.MyProcedure
(
#RowId INT = NULL OUTPUT
)
AS
INSERT INTO MyTable
(
Column1
,Column2
,...
)
VALUES
(
#Param1
,#Param2
,...
);
SET #RowId = SCOPE_IDENTITY();
You can then use this value for any subsequent inserts (alternatively, if you can pass the data all into the stored procedure, then you can use it in the remainder of the procedure body).
If you're passing the SQL in dynamically then you use much the same technique, but with a single string with statement delimiters (also ; in SQL), e.g.:
var sql = "INSERT INTO MyTable (Column1, Column2, ...) VALUES (#P1, #P2, ...);" +
"SELECT SCOPE_IDENTITY();";
Then if you execute this using ExecuteScalar you'll be able to get the identity back as the scalar result and cast it to the right type. Alternatively you could build up the whole batch in one go, e.g.
var sql = "DECLARE #RowId INT;" +
"INSERT INTO MyTable (Column1, Column2, ...) VALUES (#P1, #P2, ...);" +
"SET #RowId = SCOPE_IDENTITY();" +
"INSERT INTO MyOtherTable (Column1, ...) VALUES (#P3, #P4, ...);";
This may not be exactly the right syntax, and you may need to use SET NOCOUNT ON; at the start (my mind is rusty as I rarely use dynamic SQL) but it should get you on the right track.
The best way of doing this is the use SCOPE_IDENTITY() function in TSQL. This should be executed as part of the insert i.e.
SqlCommand cmd = new SqlCommand(#"
INSERT INTO T (Name) VALUES(#Name)
SELECT SCOPE_IDENTITY() As TheId", conn);
cmd.AddParameter("#Name", SqlDbType.VarChar, 50).Value = "Test";
int tId = (int)cmd.ExecuteScalar();
Alternatively you can assign SCOPE_IDENTITY() to a variable to be used in successive statements. e.g.
DECLARE #T1 int
INSERT INTO T (Name) VALUES('Test')
SELECT #T1 = SCOPE_IDENTITY()
INSERT INTO T2 (Name, TId) VALUES('Test', #T1)
If you are just using SQL then check Duncan's answer. If however you are using LINQ then you can create the entity, save it to the DB and the ID parameter will be populated automatically.
Given a user entity and a user table it might look like this:
using(var db = new DataContext()) {
var user = new User { Name = "Jhon" };
db.Users.InsertOnSubmit(user);
db.SubmitChanges();
/* At this point the user.ID field will have the primary key from the database */
}