update value only when changed - asp.net

I had a good look around but couldn't quite find the answer to this one:
I got a Stored Procedure that updates around 30 Fields on a SQL SERVER 2008 Table. It's important for me that one of those Fields is only getting updated, if the value actually changed.
The Stored Procedure Snippet at the moment:
ALTER PROCEDURE test
#p_RoomNo int,
[RoomNo] = #p_RoomNo,
I tried changing it for that particular Column to COALESCE / ISNULL in the SET-Clause of the Procedure, but it still Updates that Column as well
[RoomNo] = COALESCE(#p_RoomNo,RoomNo),
[RoomNo] = ISNULL(#p_RoomNo,RoomNo),
both give me the same Output ...
Do you have any ideas how to NOT Update the Value on Server Side or do I have to put this on a .asp-Forum to change the Application to not pass on any values that are unchanged?
Thanks for any input!

I think the most proper place to check whether the values changed prior to storing the new value is in the asp side of the solution, not in the database. And then you can pass a parameter to the stored procedure.
In the procedure, base on that parameter, you decide whether you should change the value or not.
Edit: Suppose you have a server control of the HiddenField type.
Page_Load(object sender, EventArgs e) {
if (IsPostBack) {
if (myTextBoxIWannaCheckForChanges.Text != myHiddenField.Value) {
// The value has changed.
}
}
}
Note that this will check for changes during the page load. You could also use that kind of logic while handling a button click (if you do so, you don't have to check for a PostBack). Like this:
foo_clicked (object sender, EventArgs args) {
SqlCommand command = // ...snip
// ... set everything you need for your command.
bool changed = (myTextBoxIWannaCheckForChanges.Text != myHiddenField.Value);
command.Parameters.AddWithValue("#changed", changed);
// ... finally let the command execute.
}

Thanks for all replies ...
Changing the Front-End-Application was no option in the end, because changes wouldn't reflect in Future Versions seeing that it's 3rd Party.
I tried most options to alter the SProc but either ran into not getting the desired Field Value updated at all (even when the Value changed) or updating all the times. I decided to look more into the problem from the other side (why I wanted this field not to be updated when the Value didn't change, which was an Update-Trigger, that should only fire when the Value of that Field actually changed.
In the end, the solution was very simple:
Seeing that the
IF UPDATE (RoomNo)
in the Trigger doesn't really compare the Value of the Field but merely if there's an Update called, I simply had to add the comparison via INSERTED and DELETED, so I added the join with DELETED, set my Where Clause on it and it works :)
ALTER trigger [dbo].[UpdateDepartDate]
on [dbo].[Customer]
for update
As
Begin
if update (RoomNo)
Begin
UPDATE Customer
SET [DepartDate] = null
FROM Rooms r
INNER JOIN Customer cu
ON cu.[RoomNo] = r.[Room_ID]
Join INSERTED INS
ON cu.[CU_ID] = INS.[CU_ID]
join Deleted Del
ON INS.[CU_ID] = DEL.[CU_ID]
WHERE INS.[RoomNo] <> DEL.[RoomNo]
END
END
Thought I post it here for anyone interested :)
Thanks again everyone for your help

Related

ASP.Net checkboxes and if statements

I am asked to develop an application where a member can select 1 plan, a combination of plans, all plans, or none.
plan1, plan2, plan3, .... plan12
I ran the truth table to find out how many possibilities there are, and it turned out to be 4096. (Ridiculous!)
My plan was to write an if statement for each possibility like this:
if (plan1.Checked == true && plan2.Checked == false && ... && plan12.Checked == false){
// insert into into table test VALUES('Plan1')
}
and so on! Obviously, there must be a better and easier way than this. Any suggestions would help. Thank you all.
If you used a CheckBoxList or similar component this would be one approach.
CheckBoxList checkBoxList = ....; // Just an example here
// You would add the different project names into the CheckBoxList
String message = "";
for (int i = 0; i < checkBoxList.Items.Count; i++) // Look at every project name
{
if (checkBoxList.Items[i].Selected) // See if it's selected
{
message += checkBoxList.Items[i].Text; // Add the name to the message
}
}
Put message in DB; // <-- Store the message into your database here
Since you're only interested in selected items you wouldn't have to deal with non-selected items at all.
Note: There is probably a better/more efficient way of creating strings than this and you might be able to use lambda expressions. This is just showing a simple approach.
Andrew_CS answer is suitable and I prefer it, but here is another way:
Handle the checked event in the code behind of all checkboxes (use one event, but allow all checkboxes to be handled by it), and depending on the sender, then you can load the information you want.
It may be that you use a Select statement to load the relevant information for each checkbox during the checkbox checked event (might be a little easier to understand than a for loop!)

Why does "SingleOrDefault" return null on second execution when there is data in DB?

I'm working on ASP.NET MVC 4.5 site using EF. I have code that checks if a record in the DB exists, and if it doesn't it creates a new record. As a result of a problem in my code which I've subsequently fixed I was calling this code twice within a fraction of a second. The result was that a duplicate record was created. Here is my code:
Word wordToUpdate = context.Words.SingleOrDefault(w => w.Label == word);
if (wordToUpdate == null) // word doesn't exist yet so make a new one
{
Word w = new Word() {
// add new word stuff here
};
context.Words.Add(w);
}
else
{
// word already exists so just add stuff to existing entry
wordToUpdate.AnnotationGroups.Add(ag);
}
context.SaveChanges();
If the word doesn't already exist in the DB it is added twice. Here are the timestamps from the duplicate records:
CreatedOn
2014-03-11 06:52:35.743
2014-03-11 06:52:50.637
I've stepped through the code while watching the DB records and the new record is added during the first execution, so:
Why is context.Words.SingleOrDefault() returning null on the second execution when there is a matching record in the DB?
Duplicate records should never exist in this table. How can I improve my code to make sure it is impossible for that to happen?
EDIT
Let me add a few details I've observed while debugging this with a breakpoint at the beginning of the code snippet above:
The first time it's called everything works as expected - since it's a new word wordToUpdate is null and a new word is added.
I stopped the code at context.SaveChanges() and checked the DB - a new row shows up with the new word added
The next call (this is an AJAX call from an Ajax.ActionLink link) fires with the same word
wordToUpdate returns null even though DB already contains that word and thus a duplicate entry for that word is added (I'm not using the word as the primary key and I'd rather handle this in code instead of trying the handle errors thrown from the DB)
When context.SaveChanges is called again another row is add to the DB
So my question is since this call is coming from the same client is the code actually being executed synchronously? The way it steps through the code in debugging seems to suggest this, but this is where my knowledge of ASP.NET gets a little fuzzy.
Maybe your problem is with the assertion you are using: w => w.Label == word.
If you are comparing objects, even though they might have same contents, == just compares if they have the same memory address, which is the default implementation. You should override Equals in the Word class so the behavior compares key values or something like that.

Cursor moves to top when refreshing list page grid

Fellow developers,
I have a custom list page, where a user can select few records, hit a button in Action pane that runs some logic in a class, and all that works fine. My problem is that the cursor does not stay at the same record but goes to the top of the grid. Sounds like a familiar issue?
I store the FormDataSource of the list page using args in the custom class that has all the logic.
I tried few things but none worked.
formDataSource.research(true)
True parameter is supposed to retain the position after research does its job. I am guessing this should have been the most straightforward solution. List page query has 2 datasources joined using Outer join and my guess is research(true) works only with Inner joins.
formDatasource.setPosition(position)
int position;
position = formDatasource.getPosition();
formDatasource.research();
formDatasource.setPosition(position);
I store the position using getPosition and set it again using setPosition. No use.
formDataSource.findRecord()
currentRecord = formDatasource.cursor();
recId = currentRecord.RecId;
formDatasource.reread();
formDatasource.research();
formDatasource.findRecord(currentRecord);
i use the ds.cursor() to get the current record and pass it to findRecord() after research(). No use.
formDataSource.findValue()
currentRecord = formDatasource.cursor();
recId = currentRecord.RecId;
formDatasource.reread();
formDatasource.research();
formDatasource.findValue(fieldNum(Table, RecId), int642str(recId));
i use the ds.cursor() to get the current record and recId and pass it to findValue() after research(). No use.
I debugged the above code and the cursor() method does get the current record and its recId.
I have started to believe that it might be a limitation of list page, and praying that somebody proves me wrong.
Any help is appreciated.
Use Method 3 but like this.
YourTable tmpTable;
currentRecord = formDatasource.cursor();
recId = currentRecord.RecId;
tmpTable = TmpTable::findByRecId(recId);
formDatasource.reread();
formDatasource.research();
formDatasource.findRecord(tmpTable);
Hope this helps.
Try to pass "true" as a parameter for the research method.
salesLine_ds.research(true) works in my case, i.e. if I research the line, cursor stays on the same line.
use the second method like this
int position;
position = formDatasource.getPosition();
//Make your update operations here
formDatasource.research(true);
formDatasource.setPosition(position);
It works for me.

Slow running web page

i created web page with dropdownlist and two gridview and on selectedindex changed event i fill the both of these gridview but in the running the both of gridview take long time to be filled.
Note:one of this gridview i created its datasource by code.
here my code snippet:
protected void _ddlPLCs_SelectedIndexChanged(object sender, EventArgs e)
{
DataTable dtStatus = new DataTable();
dtStatus = DBLayer.getMachineNameIPStatusPlCByName(_ddlPLCs.SelectedValue);
dtStatus.Columns.Add("Status", typeof(String));
foreach (DataRow row in dtStatus.Rows)
{
if (LogicLayer.checkmachineStatus(row["machineIP"].ToString()))
row["Status"] = "Online";
else
row["Status"] = "offline";
}
GVStatus.DataSource = dtStatus;
GVStatus.DataBind();
if (_ddlPLCs.SelectedValue.Contains('-'))
{
_dsPLCs.SelectParameters.Clear();
_dsPLCs.SelectParameters.Add("PLCID","0");
_dsPLCs.DataBind();
}
else
{
_dsPLCs.SelectParameters.Clear();
_dsPLCs.SelectParameters.Add("PLCID", DBLayer.getPlCIDByName(_ddlPLCs.SelectedValue).ToString());
_dsPLCs.DataBind();
}
}
pleas help me
Looking at the code, I think the problem is in this method:
LogicLayer.checkmachineStatus()
I have a hunch that this actually makes a network request to remote machines/devices to determine their status. This is going to be slow, especially if you have machines that might not be online and you have to wait for them to timeout.
If this is the culprit, what you want to do instead is build a service that runs on your server. The service should continually make these checks in the background and update a database table with the results. You probably want to include a timestamp for the last check in the table. It might even be worth inserting rather than updating, so that you have history of when status's were at different values. Your ASP.Net code should then just show the database table.
Profile! Get a trial version of RedGate ANTS and run it against your code.
If you choose line level timings, it will put a number next to each line in the code that will tell you exactly how long each line takes as a % or in milliseconds. Make sure to use wall clock time not cpu time or wait time from your datasource won't be counted properly.
I'd bet your datasource is slow.
You're doing a lot of work here...
A few random thoughts
Networks can be slow -- #Joel had a good point on that one.
One thing to check would be postback -- make sure you're only databinding on selected index changed.
Why aren't you using a 'handles' caluse in your function? Might not be a problem, just curious.
If you change your "status" column header to "online", and then use checkboxes (checked = online, unchecked = off-line, or something like that, you'll just be updating a bool value for each row, instead of a string value.
Something looks odd about how you're re-binding your dropdownlist. Because... You're using the selected value as a parameter in the gridview. Then you're subsequently re-binding the dropdown list, which potentially will result in a different selected value. Which could be causing your gridview to be databound yet again in a circuit. Not sure, as I can't see all of your code.
Anyway, FWIW. Good luck.

How do you access a dynamically built select box's selected value with jQuery?

Is there a way to get the selected value (or text, or index) of a select box that the server fills (using ASP.NET) in the client? I've tried $("#ID").val() - but the only time that works is when I continue to another page and then go back. Even then, the value that is returned is the previously selected value - if the user changes the selection, it's not registered unless they leave the page and go back. Go easy on me, I'm new at this...
Update: Tried using a regular html select, same issue (just with a populated entry). Let me elaborate on what I'm trying to do: in a separate page, I'm getting results for an autocomplete search box. The select boxes are for filters. Naturally, if the user selects a filter, I don't want to suggest items that are no longer valid. I'm looking for the keys in the ProcessRequest method of the page that contains autocomplete info.
public override void ProcessRequest(HttpContext context)
{
string respString;
string qsKey = "q";
Customer searchCust = Session[Data.Selected_Customer] as Customer;
Dictionary<string, string> qsDict = context.Request.QueryString.ToDictionary(qsKey);
Shouldn't I get the results (for instance '&ID=foo' on the last line # context.Request.QueryString?
If you want the actual selected item itself:
$("#ID option:selected");
are you sure that 'ID' is really the id of the select box ? been awhile since i used asp.net but i remember it mucked with identifiers a lot
I use the code (below) to manipulate an ASP.NET generated select box. Within the code I obtain the value of the original select box (item). Also consider using the .text() function.
var setValue = function(item){
//if value isn't already selected, postback
if(input.value != item.text())
if(select.attr('onchange'))
eval(select[0].attributes['onchange'].nodeValue);
//set input box value
$(input).val(item.text());
$(input).removeClass('empty');
//select original ASP.NET select value (hidden)
select.val(item.text());
$(lookup).hide();
//show type if present
$('.selectType').show();
};
Hope this helps.

Resources