I am trying to insert a record into my database and retrieve the GUID it just added in.
Let's say if I have a table with 3 columns, GUID, FirstName, LastName. I need to insert a new record and then get back the GUID that was just generated. The problem is that first and last name are duplicated, often. I am not quite sure how to accomplish
Here is what I tried, I know the below won't work as I am not really telling it which column to select back and I'm not sure how to tell it:
var query = #"INSERT INTO MyTable(GUID, FirstName, LastName)
SELECT
#GUID, #FirstName, #LastName);
using (var oConn = CreateConnection())
{
var test = oConn.Query<string>(query, new
{
GUID = Guid.NewGuid(),
"John",
"Doe"
}).Single();
}
The error that I get is
Sequence contains no elements
If you want only the Guid which you inserted, Why not store it in a local variable in your code and use that as needed ?
I also see some errors in your code. The below code is corrected and should work.
var guid = Guid.NewGuid();
var query = #"INSERT INTO
MyTable (GUID, FirstName, LastName) values ( #GUID, #FirstName,#LastName);";
using (var conn = CreateConnection())
{
conn.Execute(query, new { #GUID = guid, #FirstName= "John", #LastName= "Scott" });
}
// You can use the value in guid variable now. It will be Id you inserted just now
Dapper Contrib needs a Auto Generated ID, It cannot be a GUID and you cannot pass a pre generated Guid
Related
I'm building a WinForms project in C# using a PostgreSQL database and the Npgsql framework.
For inserting a record, I need to return the ID of the new record. This SO question says to add SELECT SCOPE_IDENTITY() to the query string passed to cmd. So my query string looks like this:
string insertString = "INSERT INTO sometable (company_name, category, old_value, old_desc, new_value, new_desc, reference1, reference2) VALUES (#comp, #cat, #oldValue, #oldDesc, #newValue, #newDesc, #ref1, #ref2); SELECT SCOPE_IDENTITY();";
and then get the ID with something like
int modified = cmd.ExecuteNonQuery();
But that's likely SQL Server-specific. If I use that method, I get an exception at the above line saying, "fuction scope_identity() does not exist".
I wasn't able to find anything that seemed to address this on the Npgsql documentation.
Per the linked SO question and Denis' suggestions I've tried adding both
RETURNING id;
and
CURRVAL(pg_get_serial_sequence('my_tbl_name','id_col_name'))
to the query string, replacing SELECT SCOPE_IDENTITY(); with those statements in the code above. In both cases they work as intended in DBeaver on an insert, but in my C# code in my WinForm project, modified was set to "1".
NOTE: I re-titled the question and added more information about what I've done.
Add "returning idcolumn" to the end of the sql query, then run the command with the ExecuteScalar() method instead of ExecuteNonQuery(). It should return with an int.
string insert = "insert into table1 (col1) values (something) returning idcol";
int id = cmd.ExecuteScalar();
All the comments above were almost nearly spot on and got me to a solution but didn't exactly wrap it in a bow -- so I thought i'd post my implementation that works (with silly fake example tables of course).
private int? InsertNameIntoNamesTable(string name)
{
int? id = null;
using (var dbcon = new NpgsqlConnection(_connectionString))
{
dbcon.Open();
StringBuilder sb = new StringBuilder();
var sql = $#"
insert into names_table
(name)
values
({name})
returning id;
";
sb.Append(sql);
using (var cmd = new NpgsqlCommand(sql, dbcon))
{
id = (int)cmd.ExecuteScalar();
}
dbcon.Close();
}
return id;
}
When I insert or update or delete an entity with Dapper, I need to return the id of entity.
I am using this code :
var role = await roleConnection.ExecuteAsync("UPDATE Role SET IsDelete = #isDelete, RoleName = #roleName, SecurityStamp = #securityStamp WHERE Role.Id = #id SELECT SELECT CAST(SCOPE_IDENTITY() AS INT)"
, new
{
isDelete = request.IsDelete = false,
roleName = request.RoleName,
securityStamp = Guid.NewGuid(),
id = request.Id
});
but it does not show me anything.
How can I do this?
Well, in the case of UPDATE or DELETE, you already must have the id, otherwise you couldn't be calling any of these methods - correct?
In the case of an INSERT, if your table is in SQL Server and has an INT IDENTITY column, you can use something like this:
INSERT INTO dbo.YourTable (list-of-columns)
OUTPUT Inserted.Id -- or whatever your IDENTITY column is called
VALUES (list-of-values)
and then from your C# code, use cmd.ExecuteScalar() (or ExecuteScalarAsync, if your prefer) to run this and get back a single, atomic value (the newly created id value):
var result = cmd.ExecuteScalar(....);
if (result != null)
{
int newId = Convert.ToInt32(result);
}
I Have a Form which will send Data to Multiple Table on Single Click,
Person, Education, Experience, Reference.
How can i add Data into Multiple Table so All Have Same Person ID in them,
I am Newbie and using tier Architecture, all the Database code is in DAL,, ) Working with Asp 2.0
I am thinking to doing it with a Stored procedure of Inserting into Person and getting PersonID a output parameter, but i dont know how to use that output Parameter to insert into other Tables.
My Sample COde is This
public virtual bool AddJobApplication(int JobID, string Name, string FatherName, string Phone, string Email, string Address, int AppID)
{
obj_db2.objCmd.CommandText = "AddApplication";
obj_db2.objCmd.CommandType = CommandType.StoredProcedure;
obj_db2.objCmd.Parameters.AddWithValue("JjobID", JobID);
obj_db2.objCmd.Parameters.AddWithValue("#Name", Name);
obj_db2.objCmd.Parameters.AddWithValue("#FName", FatherName);
obj_db2.objCmd.Parameters.AddWithValue("#Email", Email );
obj_db2.objCmd.Parameters.AddWithValue("#Address", Address);
obj_db2.objCmd.Parameters.AddWithValue("#Phone", Phone);
SqlParameter param = new SqlParameter("#AppID", AppID);
param.Direction = ParameterDirection.Output;
param.ParameterName = "#AppID";
param.DbType = DbType.Int32;
obj_db2.objCmd.Parameters.Add(param);
obj_db2.objCmd.ExecuteNonQuery();
}
I have this Function in DAL and i am getting param as output Paramter, I know i can access this AddJobApplication from code behind to enter form information, but not getting the point of how to use this output to insert,, Sorry if i am Taking Very Low Level but i need help.
That really depends on the architecture that's been established.
If it's easier, you can probably just return the identity of the new record instead of using an output parameter:
INSERT INTO Person (
FirstName,
LastName
)
VALUES (
'James',
'Johnson'
)
SELECT ##IDENTITY --return the identifier of the new record
If you're going to be updating multiple tables though, make sure that it's all done in the scope of a single transaction.
The stored procedure is the correct way to go about this. With the stored procedure in place you would then define the output parameter in your insert method.
Below is an example of how you might insert a blog post then get back the ID created by SQL.
Example (inserting a blog post):
public int InsertArticle(ArticleItem articleitem)
{
SqlParameter articleid = new SqlParameter(Parameters.ArticleID, SqlDbType.Int);
articleid.Direction = ParameterDirection.Output;
SqlHelper.ExecuteNonQuery(Conn, CommandType.StoredProcedure, INSERT_ARTICLE,
new SqlParameter(Parameters.Body, articleitem.Body),
new SqlParameter(Parameters.Category, articleitem.Category),
new SqlParameter(Parameters.ExpireDate, articleitem.ExpireDate),
new SqlParameter(Parameters.PublishDate, articleitem.PublishDate),
new SqlParameter(Parameters.Published, articleitem.Published),
new SqlParameter(Parameters.Section, articleitem.Section),
new SqlParameter(Parameters.Title, articleitem.Title),
articleid);
return (int)articleid.Value;
}
Calling the code
public void InsertAllTheThings()
{
var articleId = InsertArticle(articleItem); //Insert an article, return the ID
//Once you have the id, use it as needed.
var data = new SomeAwesomeData();
data.ArticleID = articleId;
data.IsAwesome = true;
InsertSomeRelatedData(data);
}
I'm not great at .NET but am learning (at least trying to! ;) ). However, this bit of code I'm working has me baffled. What I want to do is insert a row into a SQL Server 2008 database table called Comment, then use the id of this inserted row to populate a second table (CommentOtherAuthor) with new rows of data. Basically, a comment can have multiple authors.
Here's the code:
public static Comment MakeNew(int parentNodeId, string firstname, string surname, string occupation, string affiliation, string title, string email, bool publishemail, bool competinginterests, string competingintereststext, string[] otherfirstname, string[] othersurname, string[] otheroccupation, string[] otheraffiliation, string[] otheremail, bool approved, bool spam, DateTime created, string commentText, int statusId)
{
var c = new Comment
{
ParentNodeId = parentNodeId,
FirstName = firstname,
Surname = surname,
Occupation = occupation,
Affiliation = affiliation,
Title = title,
Email = email,
PublishEmail = publishemail,
CompetingInterests = competinginterests,
CompetingInterestsText = competingintereststext,
OtherFirstName = otherfirstname,
OtherSurname = othersurname,
OtherOccupation = otheroccupation,
OtherAffiliation = otheraffiliation,
OtherEmail = otheremail,
Approved = approved,
Spam = spam,
Created = created,
CommenText = commentText,
StatusId = statusId
};
var sqlHelper = DataLayerHelper.CreateSqlHelper(umbraco.GlobalSettings.DbDSN);
c.Id = sqlHelper.ExecuteScalar<int>(
#"insert into Comment(mainid,nodeid,firstname,surname,occupation,affiliation,title,email,publishemail,competinginterests,competingintereststext,comment,approved,spam,created,statusid)
values(#mainid,#nodeid,#firstname,#surname,#occupation,#affiliation,#title,#email,#publishemail,#competinginterests,#competingintereststext,#comment,#approved,#spam,#created,#statusid)",
sqlHelper.CreateParameter("#mainid", -1),
sqlHelper.CreateParameter("#nodeid", c.ParentNodeId),
sqlHelper.CreateParameter("#firstname", c.FirstName),
sqlHelper.CreateParameter("#surname", c.Surname),
sqlHelper.CreateParameter("#occupation", c.Occupation),
sqlHelper.CreateParameter("#affiliation", c.Affiliation),
sqlHelper.CreateParameter("#title", c.Title),
sqlHelper.CreateParameter("#email", c.Email),
sqlHelper.CreateParameter("#publishemail", c.PublishEmail),
sqlHelper.CreateParameter("#competinginterests", c.CompetingInterests),
sqlHelper.CreateParameter("#competingintereststext", c.CompetingInterestsText),
sqlHelper.CreateParameter("#comment", c.CommenText),
sqlHelper.CreateParameter("#approved", c.Approved),
sqlHelper.CreateParameter("#spam", c.Spam),
sqlHelper.CreateParameter("#created", c.Created),
sqlHelper.CreateParameter("#statusid", c.StatusId));
c.OnCommentCreated(EventArgs.Empty);
for (int x = 0; x < otherfirstname.Length; x++)
{
sqlHelper.ExecuteScalar<int>(
#"insert into CommentOtherAuthor(firstname,surname,occupation,affiliation,email,commentid) values(#firstname,#surname,#occupation,#affiliation,#email,#commentid)",
sqlHelper.CreateParameter("#firstname", otherfirstname[x]),
sqlHelper.CreateParameter("#surname", othersurname[x]),
sqlHelper.CreateParameter("#occupation", otheroccupation[x]),
sqlHelper.CreateParameter("#affiliation", otheraffiliation[x]),
sqlHelper.CreateParameter("#email", otheremail[x]),
sqlHelper.CreateParameter("#commentid", 123)
);
}
if (c.Spam)
{
c.OnCommentSpam(EventArgs.Empty);
}
if (c.Approved)
{
c.OnCommentApproved(EventArgs.Empty);
}
return c;
}
The key line is:
sqlHelper.CreateParameter("#commentid", 123)
At the moment, I'm just hard-coding the id for the comment as 123, but really I need it to be the id of the record just inserted into the comment table.
I just don't really understand how to grab the last insert from the table Comment without doing a new
SELECT TOP 1 id FROM Comment ORDER BY id DESC
which doesn't strike me as the best way to do this.
Can anyone suggest how to get this working?
Many thanks!
That SELECT TOP 1 id ... query most likely wouldn't give you the proper results anyway in a system under load. If you have 20 or 50 clients inserting comments at the same time, by the time you query the table again, chances are very high you would be getting someone else's id ...
The best way I see to do this would be:
add an OUTPUT clause to your original insert and capture the newly inserted ID
use that ID for your second insert
Something along the lines of:
c.Id = sqlHelper.ExecuteScalar<int>(
#"insert into Comment(......)
output Inserted.ID
values(.............)",
Using this approach, your c.Id value should now be the newly inserted ID - use that in your next insert statement! (note: right now, you're probably always getting a 1 back - the number of rows affected by your statement ...)
This approach assumes your table Comment has a column of type INT IDENTITY that will be automatically set when you insert a new row into it.
for (int x = 0; x < otherfirstname.Length; x++)
{
sqlHelper.ExecuteScalar<int>(
#"insert into CommentOtherAuthor(.....) values(.....)",
sqlHelper.CreateParameter("#firstname", otherfirstname[x]),
sqlHelper.CreateParameter("#surname", othersurname[x]),
sqlHelper.CreateParameter("#occupation", otheroccupation[x]),
sqlHelper.CreateParameter("#affiliation", otheraffiliation[x]),
sqlHelper.CreateParameter("#email", otheremail[x]),
sqlHelper.CreateParameter("#commentid", c.Id) <<=== use that value you got back!
);
}
Assuming you are using Microsoft SQL Server, you could design your table Comment so the column Id has the property Identity set to true. This way the database will generate and auto-increment the id each time a row is inserted into the table.
You would have to use the following line in your SQL request:
OUTPUT INSERTED.Id
in order to return this Id to your C# code when the request is executed.
I have an entity Report whose values I want to insert into a database table. The following attributes of Report have to be inserted:
reportID - int
RoleID - int
Created_BY = SYSTEM(default)
CURRENT_TIMESTAMP
Now the problem is with the 2nd attribute. I have a report with the LIST<ROLES> attributes. ROLES is a well defined entity which has an ID and a NAME. From this list I have to extract every role and insert each role's ID into the table.
So my query presently looks as below :
INSERT INTO REPORT_MARJORIE_ROLE(REPORT_ID, ROLE_ID, CREATED_BY, CREATED)
VALUES({0}, {1}, 'SYSTEM', CURRENT_TIMESTAMP)
The C# code from where I am parsing these values is as follows :
try
{
StringBuilder _objSQL = new StringBuilder();
_objSQL.AppendFormat(Queries.Report.ReportQueries.ADD_NEW_ROLES, report.ID, "report.MarjorieRoles.Add(MarjorieRole"));
_objDBWriteConnection.ExecuteQuery(_objSQL.ToString());
_objDBWriteConnection.Commit();
_IsRolesAdded = true;
}
So please guide me how to add roles from C# function
I'm assuming you say SQL (structured query language) and you really mean Microsoft SQL Server (the actual database product) instead - right?
You cannot insert a whole list as a whole into SQL Server - you need to insert one row for each entry. This means, you need to call the INSERT statement multiple times.
Do it like this:
// define the INSERT statement using **PARAMETERS**
string insertStmt = "INSERT INTO dbo.REPORT_MARJORIE_ROLE(REPORT_ID, ROLE_ID, CREATED_BY, CREATED) " +
"VALUES(#ReportID, #RoleID, 'SYSTEM', CURRENT_TIMESTAMP)";
// set up connection and command objects in ADO.NET
using(SqlConnection conn = new SqlConnection(-your-connection-string-here))
using(SqlCommand cmd = new SqlCommand(insertStmt, conn)
{
// define parameters - ReportID is the same for each execution, so set value here
cmd.Parameters.Add("#ReportID", SqlDbType.Int).Value = YourReportID;
cmd.Parameters.Add("#RoleID", SqlDbType.Int);
conn.Open();
// iterate over all RoleID's and execute the INSERT statement for each of them
foreach(int roleID in ListOfRoleIDs)
{
cmd.Parameters["#RoleID"].Value = roleID;
cmd.ExecuteNonQuery();
}
conn.Close();
}
let say lstroles is your LIST<ROLES>.
lstroles.ForEach(Role =>
{
/* Your Insert Query like
INSERT INTO REPORT_MARJORIE_ROLE(REPORT_ID, ROLE_ID, CREATED_BY, CREATED)
VALUES(REPORT_ID, Role.ID, {0}, {1}, 'SYSTEM', CURRENT_TIMESTAMP);
Commit you query*\
});
On a personal note: Beware of SQL Injection.