Update works only for last method call - c#

I have a quite simple UPDATE statement and it works correctly but for only one call. I have few projects (FAIs) in database and I want to change responsible person.
If I want to change two or more responsibles it only changes the responsible person for the last project. I don't have any error messages. All values are correctly send to update query but the query just does not send it to the database.
public void updateFaiUBazu(string orderNumber, FAI fai, int serialNumber)
{
konekcija.Open();
MessageBox.Show(fai.Reviewer);
komanda = new SqlCommand("
update FAI set
AircraftFK = #AircraftFK, GlassFK = #GlassFK, PartNumber = #PartNumber,
SerialNumber = #SerialNumber, ReportNumber = #ReportNumber,
Reviewer = #Reviewer, Comment = #Comment, DateTime = #DateTime,
Iges = #Iges, IgesName = #IgesName, Status = #Status
where
AircraftFK = " + fai.AircraftFK1 +
" and GlassFK = " + fai.GlassFK1 +
" and SerialNumber = " + serialNumber,
konekcija);
try
{
komanda.Parameters.Clear();
komanda.Parameters.AddWithValue("#AircraftFK", fai.AircraftFK1);
komanda.Parameters.AddWithValue("#GlassFK", fai.GlassFK1);
// komanda.Parameters.AddWithValue("#OrderNumberFK", fai[i].OrderNumerFK);
komanda.Parameters.AddWithValue("#PartNumber", fai.PartNumber);
komanda.Parameters.AddWithValue("#SerialNumber", fai.SerialNumber);
komanda.Parameters.AddWithValue("#ReportNumber", fai.ReportNumber);
komanda.Parameters.AddWithValue("#Reviewer", fai.Reviewer);
komanda.Parameters.AddWithValue("#Comment", fai.Comment);
komanda.Parameters.Add("#DateTime", fai.DateAndTime);
if (fai.IgesFile.Length != 0)
{
komanda.Parameters.AddWithValue("#Iges", fai.IgesFile);
}
else
{
komanda.Parameters.Add("#Iges", SqlDbType.VarBinary, -1);
komanda.Parameters["#Iges"].Value = DBNull.Value;
}
if (string.IsNullOrEmpty(fai.IgesName))
{
komanda.Parameters.Add("#IgesName", fai.IgesName).Value = DBNull.Value;
}
else
{
komanda.Parameters.AddWithValue("#IgesName", fai.IgesName);
}
komanda.Parameters.AddWithValue("#Status", "Not Tested");
komanda.ExecuteNonQuery();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
konekcija.Close();
}
Could that be some limitation with SqlServer update statement?

Follow a couple of steps to get to your problem.
Log yout update queries. JUst after you have created it. This will tell you if your updates are really executed when you are calling them from a loop.
If all your updates are logged, copy them to SSMS query window and execute them one by one in sequence. This would give you corect idea if there is anything wong with way queries are getting formed, or of there is any specific value in one of the parameters which is causing the problem. This will also help you identify if the problem specified by #Steve above exists.

Related

Is it bad practice to catch the "happy path" in an exception?

I have an SQL statement that checks to see if a value is in my database or not. I want to respond with the "happy path" if the value is not in the database.
I have found using DbDataReader (.NET) that if a SELECT query can't find the value it throws an exception - so my "happy path" ends up in the exception, not in the main try block.
I can always say "NOT IN" but I don't want to return all of the rows in the database that don't have the value - as this would return many thousands of results where as all I want is just a "no it is not here" type response.
public void wristbandScan(string barcode)
{
string query = "SELECT ticket FROM tickets WHERE
linked_barcode='" + barcode + "'";
ValidTicketEventArgs args = new ValidTicketEventArgs();
try
{
var queryResult = _dbRunner.queryThis(query);
args.Result = false;
args.Message = "WB already linked";
args.Barcode = barcode;
OnValidTicketEvent(args);
}
catch (Exception e)
{
this.updateWristband(barcode);
this.updateValid();
args.Result = true;
args.Message = "WB linked";
args.Barcode = barcode;
OnValidTicketEvent(args);
}
}
It feels wrong to me to catch the happy path in an error statement, but I do not want the lag associated with reading in all the rows with the NOT IN statement.
Is there a better way to do this or is this approach acceptable best practice?
Well, you don't have to fetch all the records to the client; let's extract a method for this. Assuming that you work with MS Sql:
public bool hasScanCode(string barcode) {
if (string.IsNullOrWhiteSpace(barcode))
return false;
//DONE: paramterize queries
string query =
#"SELECT ticket
FROM tickets
WHERE linked_barcode = #prm_BarCode";
using (var conn = new SqlConnection(connection_string_here)) {
conn.Open();
using (var q = new SqlCommand(conn, query)) {
//TODO: q.Parameters.Add is a better choice
q.Parameters.AddWithValue("#prm_BarCode", barcode.Trim());
using (var reader = q.ExecuteReader()) {
// we read (fetch) at most 1 record
// if empty cursor - no record with given barcode
return reader.Read();
}
}
}
}
then we can use it:
public void wristbandScan(string barcode) {
bool result = hasScanCode(barcode);
ValidTicketEventArgs args = new ValidTicketEventArgs() {
Result = result,
Message = result ? "WB linked" : "WB already linked",
Barcode = barcode,
};
OnValidTicketEvent(args);
}
Please, remember - exceptions are for exceptional situations. Exceptions are very slow (stack unrolling wants resources); they are not readable - catch, in fact, works as a notorious goto; they are dangerous - in your current code you catch too many exceptions: e.g. AccessViolationException if it's thrown somewhere within dbRunner.queryThis will be efficiently masked.
Create and call a StoredProcedure which can to handle the empty situation and return no rows instead of an exception.
Then handle the no rows scenario outside the try/catch.

SubmitChanges not updating, but inserts new record. LINQ to SQL

I am having difficulties UPDATING the databes via LINQ to SQL, inserting a new record works fine.
The code correctly inserts a new row and adds a primary key, the issue I am having is when I go to update (chnage a value that is already in the database) that same row the database is not updating, it is the else part of the code that does not work correctly. This is strange b/c the DB is properly connected and functioning through the fact that the DataContext inserts a new row with no issues. Checking the database confirms this.
This is the code,
using System;
using System.Collections.Generic;
using System.Linq;
using Cost = Invoices.Tenant_Cost_TBL;
namespace Invoices
{
class CollectionGridEvents
{
static string conn = Settings.Default.Invoice_DbConnectionString;
public static void CostDataGridCellEditing(DataGridRowEditEndingEventArgs e)
{
using (DatabaseDataContext DataContext = new DatabaseDataContext(conn))
{
var sDselectedRow = e.Row.Item as Cost;
if (sDselectedRow == null) return;
if (sDselectedRow.ID == 0)
{
sDselectedRow.ID = DateTime.UtcNow.Ticks;
DataContext.Tenant_Cost_TBLs.InsertOnSubmit(sDselectedRow);
}
else
{
// these two lines are just for debuging
long lineToUpdateID = 636154619329526649; // this is the line to be updated primary key
long id = sDselectedRow.ID; // this is to check the primary key on selected line is same
// these 3 lines are to ensure I am entering actual data into the DB
int? amount = sDselectedRow.Cost_Amount;
string name = sDselectedRow.Cost_Name;
int? quantity = sDselectedRow.Cost_Quantity;
sDselectedRow.Cost_Amount = amount;
sDselectedRow.Cost_Name = name;
sDselectedRow.Cost_Quantity = quantity;
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
}
}
}
}
And I am calling the method from this,
private void CostDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
CollectionGridEvents.CostDataGridCellEditing(e);
}
The lineToUpdateID is copied dirrectly from the database and is just there to check against the currently selected rows primary key is the same, so I know I am trying to update the same row.
I have looked through as many of the same type of issues here on SO , such as this one Linq-to-Sql SubmitChanges not updating fields … why?. But still no closer to finding out what is going wrong.
Any ideas would be much appreciated.
EDIT: Cost is just short hand of this using Cost = Invoices.Tenant_Cost_TBL;
You cannot do that. You need to get the record out of the database and then update that record. Then save it back. Like this:
else
{
// first get it
var query =
from ord in DataContext.Tenant_Cost_TBLs
where ord.lineToUpdateID = 636154619329526649
select ord;
// then update it
// Most likely you will have one record here
foreach (Tenant_Cost_TBLs ord in query)
{
ord.Cost_Amount = sDselectedRow.Cost_Amount;
// ... and the rest
// Insert any additional changes to column values.
}
}
try
{
DataContext.SubmitChanges();
}
catch (Exception ex)
{
Alert.Error("Did not save", "Error", ex);
}
Here is an example you can follow.
Or you can use a direct query if you do not want to select first.
DataContext.ExecuteCommand("update Tenant_Cost_TBLs set Cost_Amount =0 where ...", null);
Your object (Cost) is not attached to DB context. You should attach it then save changes. Check solution here

How parse Sql Script with dapper? (SET PARSEONLY ON + Dapper)

I want to check & parse sql script so I searched for that and I found something like this
SET PARSEONLY ON
SELECT * FROM [dbo].[Categories] --Query To Parse
I use dapper, so I write method like this
public bool IsValidSqlScript(string sqlScript)
{
using (SQLConnection)
{
using (SQLTransaction)
{
var status = SQLConnection.Execute("SET PARSEONLY ON " + sqlScript);
// OR
// var status = SQLConnection.Query("SET PARSEONLY ON " + sqlScript);
}
}
return status;
}
How I can get status and if exists any errors get error`s list also ???
SET PARSEONLY ON
SELECT * FR OM [dbo].[Categories] --Query To Parse
>>> false
>>> Msg 102, Level 15, State 1, Line 2 Incorrect syntax near 'FR'.
You're close, but you've got an issue with your status variable. You declare it inside your SQLTransaction using statement and then you try and return it outside of that scope.
You'll want to use a try/catch block to execute your query, that way you'll know when the sqlScript is valid or not. If you enter the catch block, it's invalid, and if you don't then it is valid.
The code should look similar to the following...
public bool IsValidSqlScript(string sqlScript)
{
bool status;
try
{
using (SQLConnection)
{
using (SQLTransaction)
{
SQLConnection.Execute("SET PARSEONLY ON " + sqlScript);
}
}
status = true;
}
catch(Exception e)
{
status = false;
)
return status;
}

How can I pause a SQLCE Query until the Table it is querying is no longer being accessed elsewhere?

I have a method that queries a table for the count of its records. QA has discovered an "edge case" where if a particular operation is canceled in a particular order and speed (as fast as possible), the GUI "forgets" about the rest of the records in that table (the contents of the tables are uploaded to a server; when each one finishes, the corresponding table is deleted).
To be clear, this table that is having records deleted from it and then queried for count ("workTables") is a table of table names, that are deleted after they are processed.
What I have determined (I'm pretty sure) is that this anomaly occurs when a record from the "workTables" table is in the process of being deleted when the workTables table is queried for the count of its records. This causes an exception, which causes the method to return -1, which in our case indicates we should cuase the GUI to not display those records.
Is there a way to check if a table is in the process of having a record deleted from it, and wait until after that operation has completed, before proceeding with the query, so that it won't throw an exception?
For those interested in the specifics, this method is the one that, under those peculiar circumstances, throws an exception:
public int isValidTable(string tableName)
{
int validTable = -1;
string tblQuery = "SELECT COUNT(*) FROM ";
tblQuery += tableName;
openConnectionIfPossibleAndNecessary();
try
{
SqlCeCommand cmd = objCon.CreateCommand();
cmd.CommandText = tblQuery;
object objcnt = cmd.ExecuteScalar();
validTable = Int32.Parse(objcnt.ToString());
}
catch (Exception ex)
{
validTable = -1;
}
return validTable;
}
...and this is the method that deletes a record from the "workTables" table after the corresponding table has had its contents uploaded:
private void DropTablesAndDeleteFromTables(string recordType, string fileName)
{
try
{
WorkFiles wrkFile = new WorkFiles();
int tableOK = 0;
DataSet workfiles;
tableOK = wrkFile.isValidWorkTable(); // -1 == "has no records"
if (tableOK > 0) //Table has at least one record
{
workfiles = wrkFile.getAllRecords();
//Go thru dataset and find filename to clean up after
foreach (DataRow row in workfiles.Tables[0].Rows)
{
. . .
dynSQL = string.Format("DELETE FROM workTables WHERE filetype = '{0}' and Name = '{1}'", tmpType, tmpStr);
dbconn = DBConnection.GetInstance();
dbconn.DBCommand(dynSQL, false);
populateListBoxWithWorkTableData();
return;
} // foreach (DataRow row in workfiles.Tables[0].Rows)
}
}
catch (Exception ex)
{
SSCS.ExceptionHandler(ex, "frmCentral.DropTablesAndDeleteFromTables");
}
}
// method called by DropTablesAndDeleteFromTables() above
public int isValidWorkTable() //reverted to old way to accommodate old version of DBConnection
{
// Pass the buck
return dbconn.isValidTable("workTables");
}
I know this code is very funky and klunky and kludgy; refactoring it to make more sense and be more easily understood is a long and ongoing process.
UPDATE
I'm not able to test this code:
lock (this)
{
// drop the table
}
...yet, because the handheld is no longer allowing me to copy files to it (I get, "Cannot copy [filename.[dll,exe] The device has either stopped responding or has been disconnected" (it is connected, as shown by ActiveStync))
If that doesn't work, I might have to try this:
// global var
bool InDropTablesMethod;
// before querying that database from elsewhere:
while (InDropTablesMethod)
{
Pause(500);
}
UPDATE 2
I've finally been able to test my lock code (copies of binaries were present in memory, not allowing me to overwrite them; the StartUp folder had a *.lnk to the .exe, so every time I started the handheld, it tried to run the buggy versions of the .exe), but it doesn't work - I still get the same conflict/contention.
UPDATE 3
What seems to work, as kludgy as it may be, is:
public class CCRUtils
{
public static bool InDropTablesMethod;
. . .
if (CCRUtils.InDropTablesMethod) return;
CCRUtils.InDropTablesMethod = true;
. . . // do it all; can you believe somebody from El Cerrito has never heard of CCR?
CCRUtils.InDropTableMethod = false;
UPDATE 4
Wrote too soon - the bug is back. I added this MessageBox.Show(), and do indeed see the text "proof of code re-entrancy" at run-time.
while (HHSUtils.InDropTablesMethod)
{
MessageBox.Show("proof of code re-entrancy");
i++;
if (i > 1000000) return;
}
try
{
HHSUtils.InDropTablesMethod = true;
. . .
}
HHSUtils.InDropTablesMethod = false;
...so my guess that code re-entrancy may be a problem is correct...

SaveChanges() not taking any affect

I'm using Entity Framework to add new records to the database, everything goes right without any exceptions, but I don't see the new record the database, here is the code:
aSham_MeterReading meterReading = new aSham_MeterReading();
meterReading.TimeStampUTC = reading.TimeOfReading;
meterReading.TimeStampLocal = reading.TimeOfReading.ToLocalTime();
meterReading.Value = reading.Reading * this.Translate(this.MeterUnitsEnum, reading.FactorIndex);
meterReading.Meter = meter;
meterReading.CreateDate = DateTime.Now;
meterReading.UpdateDate = DateTime.Now;
meterReading.RowStatus = "Active";
db.aSham_MeterReading.Add(meterReading);
db.SaveChanges();
The code above is called like 20 times per second, is there any chance that this is related to the problem?
Any help would be appreciated.
You can check for the return value from db.SaveChanges() , if it is actually successful , it returns 1 . This will let you know if the operation was actually successful or not
int returnCode = db.SaveChanges();
if(returnCode == 1 )
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Something gone wrong");
}

Categories

Resources