Using stored proc in LinqDataSource to populate GridView - c#

As in the title I need to use stored proc to feed LinqDataSource to populate result in GridView. I got this concept to work in SqlDataSource but then I had Authentication issues (I'm running the app on tablets that can't provide Integrated Authentication that SQL Server requires - and I do not want to change SQL configuration). Linq works perfectly for me except when I try to use Calendar control to feed WHERE parameter. The stored proc worked much better and I could receive correct sets but now I have problems populating that to GridView.
Here is the code:
protected void myLinqDataSource_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
DataContext myContext = new DataContext();
e.Result = myContext.myTable(myCalendar.SelectedDate);
}
protected void myCalendar_SelectionChanged(object sender, EventArgs e)
{
myLinqDataSource.DataBind();
myGridView.DataBind();
}
In this configuration the pool times out. If I move binding to event handler, there would be nothing supplied to grid view. Maybe you know a better way to use stored procs with LinqDataSources?

So since there was no answers here is one that I arrived at. LinqDataSource is great but pretty hard to configure declaratively. I used LDS dynamically to feed set into a List<>() and bound GridView to it. Worked perfectly!

Related

C# DataGridView control not updated when underlying MySQL database contents change

I am using a data-bound datagridview (sbDataGridView) control in an Windows Form based C# desktop application.
Loading data from the database is working fine and all the values are displayed correctly.
But when simulating a change of the data in the database by manually adding some rows, this change is not automatically reflected by the datagridview control. Is there a way to make the control aware of the change and update itself automatically?
I've already added some time which performs the following tasks, but none of them worked...
private void RefreshTimer_Tick(object sender, EventArgs e)
{
// tBindingSource.ResetBindings(false);
// sBindingSource.ResetBindings(false);
// sbBindingSource.ResetBindings(false);
sbDataGridView.DataSource = null;
sbDataGridView.DataSource = sbBindingSource;
//MessageBox.Show("Tick");
//sbBindingSource.ResetBindings(false);
//tBindingSource.ResetBindings(false);
//sBindingSource.ResetBindings(false);
//sbDataGridView.Refresh();
//sbDataGridView.Invalidate();
//sDataSet.Reset();
//tTableAdapter.Fill(sDataSet.t);
//sTableAdapter.Fill(sDataSet.s);
//sbTableAdapter.Fill(sDataSet.sb);
//sbDataGridView.Invalidate();
}
On the Form_Load method I have a line RefreshTimer.Start().
If uncommenting the MessageBox line, the MessageBox is shown every second. The timer is currently set to elapse every second.
(I've tried all and some of the above in various orders...)
Any ideas what's wrong here?
I already tried the "dirty" solution from C# DataGridView not updated when datasource is changed, but that did not work either.
Best regards,
Tom

SqlDataSource_OnSelected: Get data (DataTable) without re-executing the query

I have a SqlDataSource bound to a GridView with an SQL that takes about 10 seconds to retreive the data.
Also there is a UserControl called "PageSizeControl" which hooks the selected-event of the GridView's SqlDataSource. In this event, I need the DataTable to prepare some settings of the PageSizeControl.
Currently, I'm doing this with following code:
protected void ds_Selected(object sender, SqlDataSourceStatusEventArgs e)
{
SqlDataSourceView dsv = (sender as SqlDataSourceView);
dsv.Selected -= ds_Selected;
DataTable dt = (dsv.Select(DataSourceSelectArguments.Empty) as DataView).Table;
int iRowCount = dt.Rows.Count;
// some gui-adaption like visibility, text, ...
}
In older versions we used e.AffectedRows. But the value stored in e.AffectedRows is not correct when a Filter is applied to the DataSource. And we have use-cases where we don't only need the row count but the whole DataTable.
The problem is, that the .Select() re-executes the Db-Query and this takes another 10s to finish.
I also tried to turn caching on the SqlDataSource on:
EnableCaching="true" CacheDuration="Infinite"
But this wasn't helpful in two reasons:
1. The OnSelected event is not fired when cached data get accessed
2. If the OnSelected event get's fired (because data wasn't yet cached), the .Select() is still executing uncached and takes 10s.
Does anybody have clues how I can get the data without a time-consumpting re-execution of the query? Best would be in the OnSelected, but I'm open for another suggestions.
I got a workaround running that fits my requirements. I use the event GridView.OnRowDataBound and get the DataItem of the first GridRow, which contains the DataTable.
private DataTable oData = null;
protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (oData == null && e.Row.DataItem != null)
{
oData = (e.Row.DataItem as DataRowView).Row.Table;
}
}
This solution works, but it looks quite dirty and it requires a GridView (which in my case is no problem). I would be grateful for a more clean solution.
UPDATE
After a longer research with IlSpy I got to the conclusion that it is not possible to get the data in the OnSelected event. Even not if caching is enabled, since cache is written after OnSelected.
So the easiest way is to turn cache on and call the SqlDataSource.Select(...) function where you need the data.
Another way is to get the data by yourself with SqlDataSource.Select(...) and then bind the table it to the controls. But this has some disadvantages. For example: sorting and paging on GridView doesn't work out of the box when bound to a dataset/datatable.
And yet another way is to extract the data from the control which selected it. See above for an example for GridView.

Why is my LINQ query giving me old data?

I have the following code in an aspx.cs file:
protected void Page_Load(object sender, EventArgs e)
{
epdc = new edu_portalDataContext();
IQueryable<Assignment> _assignmentsList =
from assignment in epdc.Assignments
select assignment;
assignmentsList = _assignmentsList.GetEnumerator();
assignmentsList.MoveNext();
ListOfAssignments.DataSource = epdc.Assignments;
ListOfAssignments.DataBind();
}
Notes, to make it possible for you to understand the code:
Assignments is the name of the database table from which I'm pulling data.
ListOfAssignments is the ID of a Repeater control.
assignmentsList is used in the ListOfAssignments_ItemDataBound method.
Anyway, this is straightforward enough -- instantiate a data context, send it a basic query, get an enumerator, bind some data to a repeater. This part works. The next part is what confuses me.
Later on in the code, I have a click event tied to a Button control. What I want to happen is, the user enters some data in some fields, the user clicks on the button, the program makes a new record with that data, the program sends it off to the database, the database stores the new data, the Repeater (ListOfAssignments) updates with the new database data, and the user sees the new data on the page.
Here's the code in the click event:
Assignment newAssignment = new Assignment
{
//data is entered here
//...
};
epdc.Assignments.InsertOnSubmit(newAssignment);
epdc.SubmitChanges();
But here's what actually happens: when the user clicks the button, everything goes as expected, except the repeater doesn't update with the new data. I did a little debugging, and here's what I found:
assignmentsList doesn't update with the new database data. I looked around in Visual Studio's variable inspector, and the LINQ query doesn't pull in any of the new data. It's as if the user never entered anything at all. Until they refresh the page, that is: when they refresh, the Repeater updates and shows the new data.
Why doesn't the LINQ query give me fresh data on a postback?
Your click event is happening AFTER Page_Load. So the repeater is rebound before the new data is added. Do your databinding in PreRender.

DataGridView doesn't show data: DataSet is empty

I've created one project and i've used L2S. So it was working fine.
So after i'm using same connection string and creating new WinForm project. I'm placing a datagrid, selecting this connection string. I'm selecting DataMember and rows headers appears. But when i'm starting an app, i'm watching locals and i see that DataSet has all tables empty. I suggested that they will auto-populate from DB, but they doesn't. So what should I do? DB is not empty.
P.S. I've googled, really.
So it really doesn't auto-populate. I have a table "Benefits". So i've writed
private void Form1_Load(object sender, EventArgs e)
{
RadikDataSet.BenefitsDataTable benefitsDataTable = new BenefitsTableAdapter().GetData();
dataGridView1.DataSource = benefitsDataTable;
}
and it works. So tnx. It's so stupid that I should manualy call it.
Are you using a BindingSource? Make sure your assigning it in your form load event like so:
private void Form1_Load(object sender, System.EventArgs e)
{
// Bind the DataGridView to the BindingSource
// and load the data from the database.
dataGridView1.DataSource = bindingSource1;
GetData("select * from Alex_db");
}
More detailed example available here.
I am not very good with L2S but you should try to add same DB connection again in your new project in place to adding it from old project.

How do I refresh a form in c#?

I've built a form which can add/delete records to an SQL database. When I add a record, I want the form to reload and the listbox with all the records to now include the newly added record.
I googled this and saw that a new thread was recommended to refresh the form, but the instructions weren't clear enough for a newbie like me.
Any help would be appreciated.
Thanks in advance.
Edit: this is a desktop app using c# and not asp.
Some of the controls are populated by a wizard that I ran and for others I coded the datasource myself.
namespace LomWindows
{
public partial class Form1 : Form
{
SqlConnection myConnection;
public Form1()
{
InitializeComponent();
myConnection = new SqlConnection(global::LomWindows.Properties.Settings.Default.esConnectionString);
tConnStr.Text = global::LomWindows.Properties.Settings.Default.esConnectionString;
try
{
myConnection.Open();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
string sqlComm = "INSERT INTO ES_TOOL ....";
try
{
myCommand.ExecuteNonQuery();
}
catch (Exception exce)
{
Console.WriteLine(exce.ToString());
}
try
{
myConnection.Close();
}
catch (Exception exc)
{
Console.WriteLine(exc.ToString());
}
InitializeComponent();
MessageBox.Show("Tool Added");
this.Invalidate();
}
}
}
You might rebind the control again after add/edit/delete this will reload the controls with the updated data.
WinForms
There is a great article over at MSDN covering the following: Give Your .NET-based Application a Fast and Responsive UI with Multiple Threads.
When you want to Re-draw your window you can call the method Invalidate. However when you Re-bind a control; setting a new datasource, it will update the content in it.
Here are some great videos to watch for WinForms: "How Do I Videos" from WindowsClient.net.
WPF
Here is a matching article to the one in WinForms covering: Build More Responsive Apps With The Dispatcher.
Herer are some great videos to watch for WPF: "How Do I Videos", aslo from WindowsClient.net.
ASP.NET
If you want to create more responsive webbapps you might want to consider having a look at jQuery and Ajax. You can then request a new part of your web-site and replace the old one.
However if you are just doing a postback and you want to add items to your listbox, you can just call DataBind on the ListBox and it should re-bind the items in the data-source.
The underlying question isn't really about Winforms repaints, rather it's how to freshen the datasource to which the Winform controls are bound, or from which the controls are being manually populated in unbound mode, after the database has been changed by your client application.
Unless you create the data model, your datasource object has no way of knowing that the data have been changed when a DML statement is executed by a command somewhere. It all has to be "tied together". ADO.NET uses a 'disconnected recordset' model. The ADO.NET datalayer objects will raise events related to data i/o and data errors, and you must must attach listeners/eventhandlers to them; these eventhandlers must, in turn, invoke your presentation-layer code.
At present you're just scratching the surface with the command object. Best thing to do would be to read one of the books that show you how to wire up eventhandlers to the ADO.NET event model.
EDIT: Here's a link to get you started: http://msdn.microsoft.com/en-us/library/w9y9a401.aspx
If it's ASP.NET you can refresh the form by redirecting it to itself by using the following code:
Response.Redirect(Request.RawRul);
If it's a Windows Application, you need to rebind the listbox control by setting its DataSource property again.
If you're already calling Invalidate on the ListBox, you might want to add a debug statement to the Paint method to make sure it's really repainting. If it is, then you should look into where Paint gets the state needed to draw the items. Do you query the database inside Paint? (I hope not.) Or is the form keeping its state in memory somewhere? In that case, you should make sure that you're keeping the in-memory state consistent with the database.
Have you thought of the performance impact of re-loading all the rows whenever one row is added/deleted/updated? IMHO, reloading the entire data will just annoy the users and also increase the bandwidth usage. Instead, create POCO objects for each line of data. Whenever there is a (successful) CRUD operation (which you perform on the BackgroundWorker component), just add it to the DataSource and call DataBind.
For more information on how to use BackgroundWorker, see this.
Write Select query in Form_Load and call after where ever you need to refresh your form like,
form_load(Object sender,Event_args e)
{
select Query to display on Loading form
}
add_click(Object sender,Event_args e)
{
form_load(sender,e);
}

Categories

Resources