Is this SQL code concurrent safe? - sql

I am pretty sure this code is fine. I wanted to know what you guys think about the insertMediaTags function (2nd func). The things i am worried about is the below concurrent safe? and if insertMediaTags is optimize enough? note it is in a transaction due to first func but it is also in a loop which could mean its bad?
I am open to any coding practice, style or suggestions you guys may have.
(I know someone will ask, i am using sqlite ATM but its prototype code to use with mysql or a version of ms sql or another)
{
long mediaId;
//all the credentials should be verified by this point.
command.CommandText = "SELECT mediaId FROM media " +
"WHERE userId=#userId AND title=#title;";
command.Parameters.Add("#userId", DbType.Int64).Value = m.userid;
command.Parameters.Add("#title", DbType.String).Value = m.title;
if (command.ExecuteScalar() != null)
throw new System.InvalidOperationException("Title already exisit");
using (var dbTrans = connection.BeginTransaction())
{
command.CommandText =
"INSERT INTO " +
"media ( userid, catagory, creation_date, current_media_date, current_desc_date, licence, title, desc, ext) " +
"VALUES(#userid, #catagory, #creation_date, #current_media_date, #current_desc_date, #licence, #title, #desc, #ext); " +
"SELECT last_insert_rowid() AS RecordID;";
DateTime currentDate = m.creation_date;
command.Parameters.Add("#userid", DbType.Int64).Value = m.userid;
command.Parameters.Add("#catagory", DbType.Int64).Value = m.catagory;
command.Parameters.Add("#creation_date", DbType.DateTime).Value = m.creation_date;
command.Parameters.Add("#current_media_date", DbType.DateTime).Value = currentDate;
command.Parameters.Add("#current_desc_date", DbType.DateTime).Value = currentDate;
command.Parameters.Add("#licence", DbType.Int64).Value = m.license;
command.Parameters.Add("#title", DbType.String).Value = m.title;
command.Parameters.Add("#desc", DbType.String).Value = m.desc;
command.Parameters.Add("#ext", DbType.Int64).Value = m.ext;
mediaId = (long)command.ExecuteScalar();
//m.collaborateWith
insertInspired(inspireLinks.external, inspireLinks.internalPair, mediaId);
insertDerived(deriveLinks.external, deriveLinks.internalPair, mediaId);
insertMediaTags(m.listTagString, mediaId);
//command.CommandText = "END TRANSACTION;"; command.ExecuteNonQuery();
updateMediaForWatchers(m.userid, mediaId, m.catagory, currentDate);
dbTrans.Commit();
}
return mediaId;
}
void insertMediaTags(List<string> tags, long mediaId)
{
foreach(string tag in tags)
{
//assure tag exist
long tagId;
command.CommandText = "SELECT tagid FROM tag_name WHERE title=#title;";
command.Parameters.Add("#title", DbType.String).Value = tag;
object o = command.ExecuteScalar();
if (o == null)
{
command.CommandText =
"INSERT INTO tag_name(title) VALUES(#title); " +
"SELECT last_insert_rowid() AS RecordID;";
command.Parameters.Add("#title", DbType.String).Value = tag;
tagId = (long)command.ExecuteScalar();
}
else
tagId = (long)o;
command.CommandText =
"INSERT INTO media_tags(mediaId, tagid) " +
"VALUES(#mediaId, #tagid);";
command.Parameters.Add("#mediaId", DbType.Int64).Value = mediaId;
command.Parameters.Add("#tagid", DbType.Int64).Value = tagId;
command.ExecuteNonQuery();
command.CommandText =
"UPDATE tag_name SET count = count+1 "+
"WHERE tagid=#tagid";
command.Parameters.Add("#tagid", DbType.Int64).Value = tagId;
command.ExecuteNonQuery();
}
}

No it's not concurrent safe. You have a potential race condition between the SELECT to determine whether the tag exists, and the INSERT to create the tag if it does not. Imagine thread A does a SELECT and finds it does not exist, and then thread B does the same before thread A does the INSERT. Thread B will attempt the insert as well and fail.

In SQL Server, it's better to use the SCOPE_IDENTITY() function. Other than that I don't see a problem.

Related

C# Save Datatable-Object to MS-Access Database with SQL Update - Command

I save changes from my Datatableobject DT1 to my Access database, as can be seen in the following code. My problem is that I always have to run the last executing command a second time. Somehow it doesn't run correctly when run once. I have now fixed the problem in this way, but I would like to understand why that is. Does somebody has any idea?
Kind regards
foreach (DataRow DR1 in DT1.Rows)
{
if (DR1.RowState == DataRowState.Modified | DR1.RowState == DataRowState.Added | DR1.RowState == DataRowState.Deleted)
{
DA1.UpdateCommand = new OleDbCommand("UPDATE Table1 SET Column1 = #Column1, Column2 = #Column2 WHERE ID = #ID", Connection);
DA1.UpdateCommand.Parameters.Add("#Column1", OleDbType.VarChar).Value = DR1["Column1"];
DA1.UpdateCommand.Parameters.Add("#Column2 ", OleDbType.VarChar).Value = DR1["Column2 "];
DA1.UpdateCommand.Parameters.Add("#ID", OleDbType.VarChar).Value = DR1["ID"];
DA1.UpdateCommand.ExecuteNonQuery();
}
DA1.UpdateCommand.ExecuteNonQuery(); // Without this, the last command will not be executed
}

Like and = operater is not working together in signal query

I am using sap.net web form. In this web form i have a text and a button. user enter name or id and hit search button. Searching with id is working fine but with name it is not working.
What i am missing here help me out please.
String Status = "Active";
String BDstring = ConfigurationManager.ConnectionStrings["CS"].ConnectionString;
using (SqlConnection conn = new SqlConnection(BDstring))
{
try
{
String query = "SELECT * from Driver where(Name LIKE '%' + #search + '%' OR DriverID = #search) AND Status = 'Active'";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.AddWithValue("#search", SearchTextBox.Text);
conn.Open();
SqlDataReader SDR = cmd.ExecuteReader();
DataTable DT = new DataTable();
if (SDR.HasRows)
{
DT.Load(SDR);
GridView.DataSource = DT;
GridView.DataBind();
}
}
catch (SqlException exe)
{
throw exe;
}
}
}
The code is generating an exception. The fact that you're unaware of this indicates that you have "error handling" somewhere in your system that is, in fact "error hiding". Remove empty catch blocks, or pointless catch blocks such as the one in your question that just destroys some information in the exception and re-throws it. Those aren't helping you.
The actual problem is that the DriverID column is int and your parameter is varchar. So long as the varchar contains a string that can be converted to a number (which is the direction that the conversion happens in due to precedence), the query is well-formed.
As soon as the parameter contains a string that cannot be implicitly converted to a number, SQL Server generates an error that .NET turns into an exception.
For your LIKE variant, you're forcing a conversion in the opposite direction (numeric -> varchar) since LIKE only operates on strings. That conversion will always succeed, but it means that you're performing textual comparisons rather than numeric, and also means there's no possible index usage here.
I'd suggest that you change your C# code to attempt a int.TryParse on the input text and then uses two separate parameters to pass strings and (optionally) their numeric equivalent to SQL Server. Then use the appropriate parameters in your query for each comparison.
Something like:
String Status = "Active";
String BDstring = ConfigurationManager.ConnectionStrings["CS"].ConnectionString;
using (SqlConnection conn = new SqlConnection(BDstring))
{
String query = "SELECT * from Driver where(Name LIKE '%' + #search + '%' OR " +
"DriverID = #driverId) AND Status = 'Active'";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.Parameters.Add("#search", SqlDbType.VarChar,50).Value = SearchTextBox.Text;
cmd.Parameters.Add("#driverId", SqlDbType.Int);
int driverId;
if(int.TryParse(SearchTextBox.Text, out driverId))
{
cmd.Parameters["#driverId"].Value = driverId;
}
conn.Open();
SqlDataReader SDR = cmd.ExecuteReader();
DataTable DT = new DataTable();
if (SDR.HasRows)
{
DT.Load(SDR);
GridView.DataSource = DT;
GridView.DataBind();
}
}
"SELECT * from Driver where (Name LIKE '%" + #search + "%'
OR DriverID = '" + #search + "' ) AND Status = 'Active'";
how about this?

cant see gridview data that I want to see

In my Project I need that user will see the garages that in the same city of user .
I created users table that include - Id,UserName,Password,Email,CarModel,Year,City,
and another Table is GarageUsers that include -Id,UserName,Password,Email,Address,City,GarageName.
In Configure Data Source I insertes this code :
SELECT GargeUsers.GarageName, GargeUsers.Address,GargeUsers.City,GargeUsers.Email
FROM GargeUsers
INNER JOIN GarageuserCategory ON GargeUsers.Id = GarageuserCategory.UserId
I
WHERE (GarageuserCategory.CategoryId = 1) AND (GargeUsers.City LIKE Users.City)
(The GarageUserCategory is to show the data in the current category- its Ok ignore it).
In this code I see the all garages.
I add Session that save the user city when the user login.
But I cant see what I want in gridview. I need to know how to equal the session (USerCity) to garage city.
protected void LogIn_Click(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["RegistrationConnectionString"].ConnectionString);
conn.Open();
string checkuser = "select count(*) from Users where UserName= '" + UserName.Text + "'";
SqlCommand com = new SqlCommand(checkuser, conn);
int temp = Convert.ToInt32(com.ExecuteScalar().ToString());
conn.Close();
if (temp == 1)
{
conn.Open();
string checkPasswordQuery = "select Password from Users where UserName= '" + UserName.Text + "'";
SqlCommand passComm = new SqlCommand(checkPasswordQuery, conn);
string password = passComm.ExecuteScalar().ToString().Replace(" ", "");
string UserCityQuery = "select City from Users where UserName= '" + UserName.Text + "'";
SqlCommand cityComm = new SqlCommand(UserCityQuery, conn);
string UserCity = cityComm.ExecuteScalar().ToString().Replace(" ", "");
if (password == Password.Text)
{
Session["UserCity"] = UserCity;
Session["New"] = UserName.Text;
Response.Write("Password is correct");
Response.Redirect("HomePage.aspx");
}
else
{
Response.Write("Password is not correct");
}
}
else
{
Response.Write("User Name is not correct");
}
}
}
}
You say
I need that user will see the garages that in the same city of user.
That seem like you need a filter to select USER
Also you say
(The GarageUserCategory is to show the data in the current category- its Ok ignore it).
So i remove it. Next time try make the query simple with only the problem you have
SELECT
GargeUsers.GarageName,
GargeUsers.Address,
GargeUsers.City,
GargeUsers.Email
FROM
GargeUsers INNER JOIN
Users ON GargeUsers.City = Users.City
WHERE
Users.UserID = #userID <-- ADD THIS ONE
To handle variable in SQL check SELECT #local_variable (Transact-SQL)
To select the cities garage after user Select a city in the page
SELECT
GargeUsers.GarageName,
GargeUsers.Address,
GargeUsers.City,
GargeUsers.Email
FROM
GargeUsers
WHERE
GargeUsers.City = #cityID

How to Join two tables showing all records Where Table A is Not In Table B

I have a email marketing web application. I want to show which email contacts in (Table B) are not showing up in EmailContacts_Campaign (Table A). In addition, I want to filter table A by the CampaignId field. When I run the below code I get 0 records, yet I know there are a couple of thousand records there. Can anyone tell me where I am messing up?
SELECT * FROM TableA
LEFT JOIN TableB
ON TableA.EmailContactId = TableB.EmailContactId
WHERE TableA.CampaignId = 1
AND TableB.EmailContactId IS NULL
ORDER BY TableB.EmailContactId DESC
I want to show all email contacts in the EmailContact Table that are not showing up in the EmailContactCampaign table. Here is the actual code:
public List<EmailContact> GetNotAssignedContactsForCampaign(int campaignId)
{
string sqlCommand = "SELECT * FROM EmailContactCampaign LEFT JOIN EmailContact";
sqlCommand += " ON EmailContactCampaign.EmailContact_EmailContactId = EmailContact.EmailContactId";
sqlCommand += " WHERE EmailContactCampaign.EmailContact_EmailContactId = " + campaignId.ToString() AND EmailContact.EmailContactId IS NULL ;
sqlCommand += " ORDER BY EmailContact.EmailContactId DESC";
var emailContacts = new List<EmailContact>();
string CS = db.Database.Connection.ConnectionString;
using (SqlConnection con = new SqlConnection(CS))
{
con.Open();
SqlCommand cmd = new SqlCommand(sqlCommand, con);
//Create sql datareader
using (SqlDataReader sqlDataReader = cmd.ExecuteReader())
{
while (sqlDataReader.Read())
{
var emailContact = new EmailContact();
emailContact.Assigned = ((bool)sqlDataReader["Assigned"]);
emailContact.Cell1 = _crypto.DecryptAndSanitize(sqlDataReader["Cell1"] as string);
emailContact.Cell2 = _crypto.DecryptAndSanitize(sqlDataReader["Cell2"] as string);
emailContact.City = _crypto.DecryptAndSanitize(sqlDataReader["City"] as string);
emailContact.Company = _crypto.DecryptAndSanitize(sqlDataReader["Company"] as string);
emailContact.EmailAddress = _crypto.DecryptAndSanitize(sqlDataReader["EmailAddress"] as string);
emailContact.EmailContactId = (int)sqlDataReader["EmailContactId"];
emailContact.FullName = _crypto.DecryptAndSanitize(sqlDataReader["FullName"] as string);
emailContact.Hold = (bool)sqlDataReader["Hold"];
emailContact.Phone1 = _crypto.DecryptAndSanitize(sqlDataReader["Phone1"] as string);
emailContact.Phone2 = _crypto.DecryptAndSanitize(sqlDataReader["Phone2"] as string);
emailContact.State = _crypto.DecryptAndSanitize(sqlDataReader["State"] as string);
emailContact.Status = (Status)sqlDataReader["Status"];
emailContact.Zip = _crypto.DecryptAndSanitize(sqlDataReader["Zip"] as string);
emailContacts.Add(emailContact);
}
}
return (emailContacts);
}
}
Have you tried this?
SELECT * FROM tableB WHERE EmailContactId NOT IN (SELECT EmailContactId FROM tableA)
i think you got 0 probably because of this AND TableB.EmailContactId IS NULL
Please try this one
SELECT * FROM TableA
LEFT JOIN TableB
ON TableA.EmailContactId = TableB.EmailContactId
WHERE TableA.CampaignId = 1
ORDER BY TableB.EmailContactId DESC
I'm sorry my question was not clear enough. Did some digging and found the answer on another post. Sorry but I accidentally closed it and can't find it again. Anyway, here is my implementation of it.
SELECT * FROM EmailContact
WHERE NOT EXISTS
(SELECT * FROM EmailContactCampaign WHERE EmailContactCampaign.EmailContact_EmailContactId = EmailContact.EmailContactId AND EmailContactCampaign.Campaign_CampaignId = 1)
If i understood your question correctly, you are looking for B's that are not in A. But your query will return A's that are not in B. Turn it aroung (tableB left join tableA where a... is NULL)
Your problem was that you had it the wrong way around: your query would return all contacts from EmailContactCampaign that were not in EmailContact.
The correct solution for your problem would look like this:
SELECT * FROM EmailContact
WHERE EmailContactId NOT IN (
SELECT EmailContact_EmailContactId FROM EmailContactCampaign
WHERE Campaign_CampaignId = ?
)
ORDER BY EmailContact.EmailContactId DESC

How to bulk insert geography into a new sql server 2008 table

I have a very large shape file with hundreds of thousands of rows of polygons and other associated data, like formatted addressing and APN numbers. How do I get this data into a table with geography without using things like Shape2SQL? I can't very well run an insert statement for every row that would take forever, the optimal solution would be to create a csv or a properly formatted bin file and then do a bulk insert, or bcp, or openrowset, but try, try, try as I might I cannot get a csv file or bin file to work. Can anybody help?
The following code is the best I could manage.
SqlGeographyBuilder sql_geography_builder = new SqlGeographyBuilder();
sql_geography_builder.SetSrid(4326);
sql_geography_builder.BeginGeography(OpenGisGeographyType.Polygon);
sql_geography_builder.BeginFigure(-84.576064, 39.414853);
sql_geography_builder.AddLine(-84.576496, 39.414800);
sql_geography_builder.AddLine(-84.576522, 39.414932);
sql_geography_builder.AddLine(-84.576528, 39.414964);
sql_geography_builder.AddLine(-84.576095, 39.415015);
sql_geography_builder.AddLine(-84.576064, 39.414853);
sql_geography_builder.EndFigure();
sql_geography_builder.EndGeography();
SqlGeography sql_geography = new SqlGeography();
sql_geography = sql_geography_builder.ConstructedGeography;
FileStream file_stream = new FileStream("C:\\PROJECTS\\test.bin", FileMode.Create);
BinaryWriter binary_writer = new BinaryWriter(file_stream);
sql_geography.Write(binary_writer);
binary_writer.Flush();
binary_writer.Close();
file_stream.Close();
file_stream.Dispose();
SqlConnection sql_connection = new SqlConnection(connection_string);
sql_connection.Open();
SqlCommand sql_command = new SqlCommand();
sql_command.Connection = sql_connection;
sql_command.CommandTimeout = 0;
sql_command.CommandType = CommandType.Text;
sql_command.CommandText = "INSERT INTO [SPATIAL_TEST].[dbo].[Table_1] ([geo]) " +
"SELECT [ors].* " +
"FROM OPENROWSET(BULK 'C:\\PROJECTS\\AMP\\test.bin', SINGLE_BLOB) AS [ors] ";
sql_command.ExecuteNonQuery();
sql_command.Dispose();
sql_connection.Close();
sql_connection.Dispose();
But this only lets me import singularly the polygon--I need everything else as well.
Well after several days of headache I have come to the conclusion that there is no answer. Not even the mighty ESRI has any clue. Thankfully I did come up with a different soultion. In my table definition I created an NVARCHAR(MAX) column to hold the WFT of my geography and added that WFT to my csv file, and then after the bulk insert I run a table wide update statment to convert tht WFT to the actual geography type. Also adjust the csv file to use a different character besides a , to separate with becuase the WFT contains ,'s
SqlGeographyBuilder sql_geography_builder = new SqlGeographyBuilder();
sql_geography_builder.SetSrid(4326);
sql_geography_builder.BeginGeography(OpenGisGeographyType.Polygon);
sql_geography_builder.BeginFigure(-84.576064, 39.414853);
sql_geography_builder.AddLine(-84.576496, 39.414800);
sql_geography_builder.AddLine(-84.576522, 39.414932);
sql_geography_builder.AddLine(-84.576528, 39.414964);
sql_geography_builder.AddLine(-84.576095, 39.415015);
sql_geography_builder.AddLine(-84.576064, 39.414853);
sql_geography_builder.EndFigure();
sql_geography_builder.EndGeography();
SqlGeography sql_geography = new SqlGeography();
sql_geography = sql_geography_builder.ConstructedGeography;
StreamWriter stream_writer = new StreamWriter("C:\\PROJECTS\\AMP\\test.csv");
stream_writer.AutoFlush = true;
stream_writer.WriteLine("1?123 TEST AVE?" + sql_geography.ToString() + "?");
stream_writer.Flush();
stream_writer.WriteLine("2?456 TEST AVE?" + sql_geography.ToString() + "?");
stream_writer.Flush();
stream_writer.WriteLine("9?789 TEST AVE?" + sql_geography.ToString() + "?");
stream_writer.Flush();
stream_writer.Close();
stream_writer.Dispose();
SqlConnection sql_connection = new SqlConnection(STRING_SQL_CONNECTION);
sql_connection.Open();
SqlCommand sql_command = new SqlCommand();
sql_command.Connection = sql_connection;
sql_command.CommandTimeout = 0;
sql_command.CommandType = CommandType.Text;
sql_command.CommandText = "BULK INSERT [SPATIAL_TEST].[dbo].[Table_1] " +
"FROM 'C:\\PROJECTS\\AMP\\test.csv' " +
"WITH (FIELDTERMINATOR = '?', ROWTERMINATOR = '\n') " +
"" +
"UPDATE [SPATIAL_TEST].[dbo].[Table_1] " +
"SET [geo] = geography::STPolyFromText([geo_string], 4326) ";
sql_command.ExecuteNonQuery();
sql_command.Dispose();
sql_connection.Close();
sql_connection.Dispose();
MessageBox.Show("DONE");
}
catch (Exception ex)
{ MessageBox.Show(ex.Message); }