问题
In my application a user will insert a book. For example someBook will be insert with 3 copies. Table1.BookID = 1, Table1.Copy = 3, Then in another table those 3 books will have their primary key so it will be Table2.AccessionID = 1,2,3 Table2.BookID = 1, 1, 1.
This is what I current doing but a bad practice as what Aaron Bertrand said.
int BookTitlesID;
public void addBookTitle()
{
int copy = int.Parse(textBox2.Text);
try
{
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand1 = new SqlCommand("INSERT INTO BookTitles(BookTitle, Copies) Values(@BookTitle, @Copies)", myDatabaseConnection))
{
mySqlCommand1.Parameters.AddWithValue("@BookTitle", BookTitletextBox.Text);
mySqlCommand1.Parameters.AddWithValue("@Copies", copy);
mySqlCommand1.ExecuteNonQuery();
}
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "Exception");
}
}
public void addBook()
{
int copy = int.Parse(textBox2.Text);
try
{
for (int x = 0; x < copy; x++)
{
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand1 = new SqlCommand("INSERT INTO book(BookTitleID) Values(@BookTitleID)", myDatabaseConnection))
{
mySqlCommand1.Parameters.AddWithValue("@BookTitleID", BookTitlesID);
mySqlCommand1.ExecuteNonQuery();
}
}
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "Exception");
}
}
private void Form_Load(object sender, EventArgs e)
{
using (SqlConnection myDatabaseConnection = new SqlConnection(myConnectionString.ConnectionString))
{
myDatabaseConnection.Open();
using (SqlCommand mySqlCommand1 = new SqlCommand("SELECT TOP 1 BookTitleID + 1 FROM BookTitles ORDER BY BookTitleID DESC", myDatabaseConnection))
{
string x = mySqlCommand1.ExecuteScalar().ToString();
BookTitlesID = Convert.ToInt32(x);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
addBookTitle();
addBook();
}
回答1:
Simplify. Most notably, as discussed in your other, related question, there is absolutely no safety in going out and seeing what the current MAX is, adding 1, and assuming that will be the next identity value generated. You can only rely on that number if you retrieve it after you have inserted, and the most reliable way to do that is to use SCOPE_IDENTITY() (or, for a multiple-row INSERT, an OUTPUT clause).
CREATE PROCEDURE dbo.InsertBook
@BookTitle NVARCHAR(256),
@Copies INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @BookTitleID INT;
INSERT dbo.BookTitles(BookTitle, Copies) SELECT @BookTitle, @Copies;
SELECT @BookTitleID = SCOPE_IDENTITY();
INSERT dbo.Books(BookTitleID) SELECT @BookTitleID
FROM (SELECT TOP (@Copies) rn = ROW_NUMBER() OVER (ORDER BY [object_id])
FROM sys.all_objects ORDER BY [object_id]) AS y;
END
GO
Now you can really simplify your C# code (I'm not a C# guy, so whether this is the best approach or if it will even compile is beyond me, but hopefully you can sort that out on your own).
public void addBook()
{
try
{
int Copies = int.Parse(textBox2.Text);
string BTitle = BookTitletextBox.Text
using (SqlConnection conn = new SqlConnection ...blah blah...)
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("EXEC dbo.InsertBook", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@BookTitle", BTitle);
cmd.Parameters.AddWithValue("@Copies", Copies);
cmd.ExecuteNonQuery();
}
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message, "Exception");
}
}
private void button1_Click(object sender, EventArgs e)
{
addBook();
}
来源:https://stackoverflow.com/questions/18195528/right-approach-to-insert-in-table-then-copy-it-to-another-table