I have recently allocated a work of letting employees filled their entries for a month.
I have a grid having 30,31,27,28 column based on month selected. User adds a row,selects a task from grid view row drop-down and fills his time sheet for the particular day of the selected month.
On page load if user has previously submitted some entries i take those entries in a data table,store the datatable in session using Session["TimeSheet"]=data table name and bind the data table with the grid.If its for the first time then also a blank datatable with default schema is created and it is binded to the session using the same Session["TimeSheet"]=data table name. Thus it is guaranteed that Session variable will have some data table stored.
On every add button click i fetch data table from session variable,add a new row in the data table and bind the grid.But to my badluck sometime my add button gets Session["TimeSheet"] as null and Sometimes not.
But if i'm guranteed to have stored datatable in Session how come it is coming null sometimes in Session Variable. I have used break point and found that Session variable is always set on page load. But why on add button click it is not working.....I have seen other stackoverflow tags also they said to check webgarden,WebFarm,Application domain recycling. But as if now its not even working in default VS development server.
Please help. I'm stuck in this problem from last 3 days......
private object obj = null;
private object mySession
{
get
{
if (obj == null)
{
obj = new object(); //OR
obj = Session["Session"];
//Initialise your object with default value
}
return obj;
}
set
{
obj = value;
}
}
Use mySession varibale in your code where you required
DataSet ds = mySession as DataSet;
//as you required you can typecast
Related
This concerns an approval field on a form. In the database, it's a bool field, an int field containing a FK to approvers, and a date-time field that, together, indicate whether something was approved and if so, who approved it and when. On the form, this has to translate into something like "Approved by John Smith on 01/02/03 04:05."
I handle this with a navigation bar. When the binding source position changes, the event is trapped and the code formats the calculated fields, like this (what the code does it not that important).
private void ctlNavBar1_displayCurrent(object sender, EventArgs e)
{
var drv = talsBindingSource.Current as DataRowView;
if (drv != null)
{
ctlBoundCheckButton1.lblText = $"Submitted {drv.Row.Field<DateTime>("SubmitDate").ToString("MM/dd/yy hh:mm tt")}";
ctlBoundCheckButton1.setControls(true);
if (drv.Row.Field<bool>("Approved"))
{
var sup = talsSupervisorsBindingSource.Current as DataRowView;
ctlBoundCheckButton2.lblText = $"Approved by {sup.Row.Field<string>("FullName")} on {drv.Row.Field<DateTime>("ApproveDate").ToString("MM/dd/yy")}";
ctlBoundCheckButton2.setControls(true);
}
}
else
{
using (DialogCenteringService centeringService = new DialogCenteringService(this))
{
MessageBox.Show("No TALs to Approve", "Confirm", MessageBoxButtons.OK);
}
Close();
}
}
The problem is that
public TALsApprove()
{
InitializeComponent();
talsTableAdapter.FillForApproval(timeTrackDataSet.TALs, User.ID);
usersTableAdapter.FillBySupervisor(timeTrackDataSet.Users, User.ID);
timeSlipsTableAdapter.FillBySupervisor(timeTrackDataSet.TimeSlips, User.ID);
ctlNavBar1.displayCurrent += ctlNavBar1_displayCurrent;
ctlNavBar1.bindingSource = talsBindingSource;
// this assignment doesn't fire Position Changed (or anything else, as far as I can tell)
}
the binding source event PositionChanged does not fire when the binding source is first assigned. I've worked around that by using the form Shown event, like this.
private void TALsApprove_Shown(object sender, EventArgs e)
{
ctlNavBar1_displayCurrent(null, new EventArgs());
}
So my questions are:
1.- Does calling event handlers directly like this mess with any of .NET's internals? (e.g. memory leaks, stack problems, etc.)
2.- Is there a less kludgy way of handling the calculation of fields when the binding source is first initialized, as well as when the contents of the current record change? I experimented with the binding source events CurrentChanged and CurrentItemChanged, but they seem to over-fire, firing even when no actual field value had changed.
There are a couple of ways I might think to tidy this up:
1 ) Use a calculated column
Assumptions:
You have a strongly typed DataSet with two tables like Applications and Users
You have the following columns in Applications: Approved(bool), ApproveDate(datetime), ApprovedByUserId(int)
You have a single datarelation between Applications and Users that maps Applications.ApprovedByUserId (many) to User.UserId (one), and UserId is also an int
Process:
In your dataset click in your Applications table, and add a string column
Set its Expression property to something like: IIF([Approved] = False,'Not approved','Approved by' + Parent.Username + ' on ' + [ApproveDate])
You have some process alreadythat fills good data into the table:
When you run the app it becomes the datatable's problem to build the narrative:
Let's edit another detail in at runtime:
When you finish the edit and move off the row it will be committed to the table and the narrative updates automatically
You can read more about what syntax you can use in DataColumn.Expression
If you don't have a bool approved you could add one or use some other test like IIF(ApprovedByUserId IS NULL,'Not Appproved,'App...'). If yo uhave multiple datarelations coming off Applications you specify the name of the relation after Parent like Parent(App_User).UserName` assuming the datarelation is called App_User
Bind different things on the UI
Noone ever said you only had to bind Text. If you had a "Approved" bool column in your dataset, you could have several labels in a row:
--label1----- --label2------ --label3-- --label4--
"Approved by" BindParentName " on " BindDate
You can bind every one of their Visible properties to the Approved bool so the labels disappear if the user navs to an unapproved row.
The easiest way to get the parent user name into the Applications data table (because all these labels are bound to a indingsource that sits on the Applications table, right?) is to use an Expression on a new column like above, but simpler (just Parent.UserName or Parent(App_User).UserName`) to import the user name into the Applications datatable.
There are other ways, involving multiple binding sources that bind to datarelations.. We can even jiggle a combo box into doing it - the combo has a DataSource of the users table, but a DataMember of "ApprovedByUserId" from the applications table; it will perform 2 way lookup of the ApprovedByUserId <--> UserId equivalence
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I allow a user to download some data to csv. They can then edit some columns and then upload it back. I need a speed efficient way to compare certain columns between like objects to see what changed.
Currently I pull the original data from the DB and make it a list so it's all in memory. There is about 100k items so it's not that bad. That part takes less than a second. Then I load in the csv file and put it to list. Both lists have the same class type.
Then I loop over the csv data (as they probably removed some rows which they didn't change but they could still have changed a lot of rows). For each row in the csv list I query the list that came from the DB to find that object. Now I have the csv object and the object from the database as the same structure. Then I run it through a custom object compare function that looks at certain columns to see if anything changed.
If something did change I have to validate what they entered is a valid value by query another reference list for that column. If it's not valid I write it out to an exceptions list. At the end if there are no exceptions I save to db. If there are exceptions I don't save anything and I show them the list of errors.
The detail compare provides a list of columns and the old vs new values that changed. I need this to query the reference list to make sure the new value is valid before I make the change. It's fairly inefficient but it gives great detail to the user about what may be an issue with an upload which is very valuable.
This is very slow. I'm looking for ways to speed it up while still being able to give the user detailed information about why it may have failed so they can correct it.
// get all the new records from the csv
var newData = csv.GetRecords<MyTable>().ToArray();
// select all data from database to list
var origData = ctx.MyTable.Select(s => s).ToList();
// look for any changes in the new data and update the database. note we are looping over the new data so if they removed some data from the csv file it just won't loop over those and they won't change
foreach (var d in newData)
{
// find data so we can compare between new (csv) and current (from db) to see what possibly changed
var oData = (from o in origData
where o.id == d.id
select o).FirstOrDefault();
// only the columns in the updatableColumns list are compared
var diff = d.DetailedCompare(oData, comparableColumns.ToList());
if (diff.Count > 0)
{
// even though there are differences between the csv record and db record doesn't mean what the user input is valid. only existing ref data is valid and needs to be checked before a change is made
bool changed = false;
// make a copy of this original data and we'll check after if we actually were able to make a change to it (was the value provided valid)
var data = CopyRecord(oData);
// update this record's data fields that have changed with the new data
foreach (var v in diff)
{
// special check for setting a value to NULL as its always valid to do this but wouldn't show up in ref data to pass the next check below
if (v.valA == null)
{
oData.GetType().GetProperty(v.Prop).SetValue(oData, v.valA);
oData.UpdatedBy = user;
oData.UpdatedDate = DateTime.Now;
changed = true;
}
// validate that the value for this column is in the ref table before allowing an update. note exception if not so we can tell the user
else if (refData[v.Prop].Where(a => a.value == v.valA.ToString()).FirstOrDefault() != null)
{
// update the current objects values with the new objects value as it changed and is a valid value based on the ref data defined for that column
oData.GetType().GetProperty(v.Prop).SetValue(oData, v.valA);
oData.UpdatedBy = user;
oData.UpdatedDate = DateTime.Now;
changed = true;
}
else
{
// the value provided isn't valid for this column so note this to tell the user
exceptions.Add(string.Format("Error: ID: {0}, Value: '{1}' is not valid for column [{2}]. Add the reference data if needed and re-import.", d.id, v.valA, v.Prop));
}
}
// we only need to reattach and save off changes IF we actually changed something to a valid ref value and we had no exceptions for this record
if (changed && exceptions.Count == 0)
{
// because our current object was in memory we will reattached it to EF so we can mark it as changed and SaveChanges() will write it back to the DB
ctx.MyTable.Attach(oData);
ctx.Entry(oData).State = EntityState.Modified;
// add a history record for the change to this product
CreateHistoryRecord(data, user);
}
}
}
// wait until the very end before making DB changed. we don't save anything if there are exceptions or nothing changed
if (exceptions.Count == 0)
{
ctx.SaveChanges();
}
The first big win would be to put your data in a dictionary so you can get to the desired value quickly by ID, without having to search for the object through thousands of objects. I'm pretty sure it'll be faster.
Beyond that I suggest you run your code through a profiler to determine exactly which parts are the slowest. It's entirely possible that DetailedCompare() does something that's terribly slow but may not be obvious.
One thing to consider is having asynchronous compares and or asynchronous if (diff,Count > 0) at least the latter assuming that there are a few random changes why wait for all the copying and reflection. Put it in a seperatge function and have run parallel.
I have a page which has a text box at the top. When the page is loaded, the code runs for the value of text box i.e Textbox.text= something. The logic of that code is:
bring the last value of the specific column of specific table from database (Integer always)
add 1 to it
show in text box.
It works perfectly fine. But I want to know that if two users are accessing the same page how should I handle this scenario when page is loaded.
Example the last value in DB column was 8 when the page loaded it incremented it and showed 9 in text box.
But what if two users loaded the page same time on different browsers it will cause problem because I don't want duplicate in my columns.
What you can do here is before you insert into db first get the last value from the colum and then +1 the value and then insert it into db.
but there is one catch which is if your User1 and User2 are seeing 8 value in textbox and User1 clicks on button 9 will get stored in db column and then User2 clicks on button 10 value will get stored.
Your best bet would be to load the database value into memory (e.g. a static variable) and have a method that uses a lock before incrementing and returning the result to the respective users. e.g.
private static object _syncRoot = new object();
private static int? dbValue;
public static int GetNewDbValue()
{
if (dbValue == null)
{
// load db value from database
}
// lock ensures only one user can increment at a time
lock (_syncRoot)
{
dbValue++;
return dbValue;
}
}
This will work as long as you are not running a web farm or load balancing. If you want to stay away from static, by all means you can, just make sure the object you use instead is centrally accessible.
I am building LINQ to SQL and its run against SQlite database. I need to remove repeating column values from the dataset. Basically the value would be shown for the first row in the dataset and blanked for each subsequent row that had the same value.
I read about using break but I am not sure how to write it up or if it can be used. I read other threads addressing the same issue but was not able to come up with a solution for my scenario.
Should I just retrieve the dataset and suppress them in C# code?
If so I need help/pointers to do that.
If you are displaying this data in an SSRS report (.RDLC), set the HideDuplicates property of the text box that shows the data to either the name of the dataset or the grouping it's in (to show the value at the start of a new group).
You could loop through the result and set a local variable of
string lastValue = null;
foreach(var row in rows)
{
if(lastValue == row.SomeColumn)
{
row.SomeColumn = null;
}
else
{
lastValue = row.SomeColumn
}
}
Probably others ways, but hard to say without more context of what you have so far.
Have you tried using Linq to get the values from your table using the Distinct Method?
I'm having some trouble getting my DataSet to work.
I have a MDB-Database in the background and created a DataSet out of it. Now I created a new method that lets me create a new user in the table.
But when I call it, nothing happens. No exceptions, no errors and I even get "1" returned as number of affected rows. But when I look in the database, no user was added.
I have the feeling that I miss to somehow tell the DataSet that I want to operate the Database itself rather than just the internal DataSet... How can I achieve this?
// DataSet1 uses the connection to the Database.mdb
// Created by the Designer
// The Users table has 3 columns, id, name and password
DataSet1 set = new DataSet1();
UsersTableAdapter adap = new UsersTableAdapter();
DataSet1.UsersRow row = set.Users.AddUsersRow("asd", "asd");
int count = adap.Insert("das", "das");
MessageBox.Show(row.RowState.ToString() + ": " + count.ToString());
count = adap.Update(set.Users);
set.AcceptChanges();
MessageBox.Show(row.RowState.ToString() + ": " + count.ToString());
// The Messagebox shows: "Added: 1"
// The second one: "Unchanged: 1"
MessageBox.Show(set.Users.Rows.Count.ToString());
// Returns "2"...
Not knowing too much about your code, try reading this how to from MSDN:
http://msdn.microsoft.com/en-us/library/ms233812(v=VS.80).aspx
Update: with data sets, what would normally happen (assuming the data set has been populated) is rows would be added, edited, or deleted in code. These rows would have a corresponding RowState signifying them as added, edited, deleted, or unmodified. During the .Update the associated table adapter, complete with associated insert/update/delete commands, will iterate the rows and execute the command on a given row depending on the row's state. When the rows have been iterated, .AcceptChanges is called, reverting the row state's to default.
If you call AcceptChanges before updating, then nothing will happen. The RowState of each row will be lost so the .Update will not have the required information it needs to perform the update to the database. If you have custom code for wrapping it all in a transaction, then you need to make sure you commit the transaction.
In your example, you seem to imply you are using the table adapter and not the data set itself. I would advise against this - the table adapters usually place methods on the tables in a data set that you should use.
Update 2: the code looks OK to me, though you don't need to call Insert on the adapter, or AcceptChanges after the update (the latter is done automatically). This leads me to believe there is a bug in your insert command SQL - try extracting the SQL used by the command and run it manually against the database.
Update 3: the following code works fine for me:
static void Main(string[] args)
{
db1DataSet set = new db1DataSet();
set.Users.AddUsersRow("asd", "asd");
foreach (DataRow row in set.Users.Rows)
{
object foo = row.RowState; // Confirm row state in debugger.
}
UsersTableAdapter adap = new UsersTableAdapter();
adap.Update(set.Users);
Console.Read();
}