Adding User input to List then populating Gridview - c#

I have an 3 tier application (DAL, BBL, UI)
BBL at the moment do Nothing just a pass-thru
I have a grid view and for simplicity's sake one text box(TB) and one drop down list(DDL).
and Two submit buttons.
(I changed my Custom Class to Object. just for this example)
First Submit button adds the TB.text & DDL.SelectedValue to a Object X in the UI.
the BBL takes that object X to adds it to a List(X) in the BBL.
Then the BBL should populate the Gridview with the List(X). (with ajax partial page load)
the second Submit should send the full List(X) to the database.
The problem im having is when I click the first Submit(the local) I dont get new Rows just keep over writing the same row. what am I Missing?
in the UI class
private businesslogic blogic = new businesslogic();
protected void B1_local_Click(object sender, EventArgs e)
{
object x = new object();
x.id = Convert.ToInt32(TB_1.Text);
x.var1 = Convert.ToInt32(DDL_1.SelectedValue);
blogic.addrowtolist(x);
Gridview1.DataSource = blogic.grablist();
Gridview1.Databind();
}
in the BBL class
public List<object> locallist = new List<object>();
public void addrowtolist(object x)
{
locallist.Add(x);
}
public List<object> grablist()
{
return locallist;
}

With every postback, you're loading a new BL with a new (empty) List. To see your List grow, you're going to need to save it somewhere that persists (doesn't disappear) between one request and the next.
I would recommend putting your List in a Session key
Session["items"] = blogic.locallist;
and then pulling it out and sending it to a second BL constructor on postback. This is probably simplest, but not always the correct approach.
http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx

Related

C# Showing Data in DatagridView?

This is my Form 1
When I click on the last row it shows data on the second grid control, Now I Want to Show this Data on the following Form (form 2 (Form with Purchase Written on Orange Color)) datagridview How can I do this.
table.Columns.Add("Item Name", Type.GetType("System.String"));
table.Columns.Add("Main Qty", Type.GetType("System.Decimal"));
table.Columns.Add("Price", Type.GetType("System.Decimal"));
table.Columns.Add("Per", Type.GetType("System.String"));
table.Columns.Add("Basic Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Dis Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Dis Percentage", Type.GetType("System.Decimal"));
table.Columns.Add("Tax Amount", Type.GetType("System.Decimal"));
table.Columns.Add("Net Value", Type.GetType("System.Decimal"));
dataGridView1.DataSource = table;
Above is the Form Load of (form 2)
And Below is the RowClick of Form 1
private void gridView1_RowClick(object sender, DevExpress.XtraGrid.Views.Grid.RowClickEventArgs e)
{
try
{
FRM_Purchase frm = new FRM_Purchase();
var ctx = new BizPlusEntities();
int GettingIdForShowing = (int)gridView1.GetRowCellValue(e.RowHandle, "PurchaseID");
var GettinginToDatabase = ctx.Purchases.Where(x => x.PurchaseID == GettingIdForShowing).ToList();
foreach (var item in GettinginToDatabase)
{
frm.txtPartyName.Text = item.PartyName;
frm.txtDate.Text = item.Date.ToString();
frm.txtTerms.Text = item.Terms;
frm.txtSeries.Text = item.Series;
frm.txtDueDate.Text = item.DueDate.ToString();
frm.txtPinvoice.Text = item.Pinvoice.ToString();
UniqueIdentifier = item.UniquePurchaseNumber;
string SelectingUniqueIdentfier = ctx.Purchases.SingleOrDefault(x => x.PurchaseID == item.PurchaseID)?.UniquePurchaseNumber ?? "Nulled";
var GettingInItems = ctx.ItemPurchaseDatas.Where(x => x.UniquePurchaseNumber == SelectingUniqueIdentfier).ToList();
foreach (var Sam in GettingInItems)
{
TItemName = Sam.ItemName;
TMainQty = Sam.MainQty ?? 0;
TPrice = Sam.Price ?? 0;
TPer = Sam.Per;
TBasicAmount = Sam.BasicAmount ?? 0;
TDisAmt = Sam.DisAmount ?? 0;
TDisP = Sam.DecimalPercentage ?? 0;
TTaxAmount = Sam.Gst ?? 0;
TTotalAmount = Sam.TotalAmount ?? 0;
}
frm.Show();
}
}
catch (Exception)
{
throw;
}
}
The problem is When I do frm.Table.Rows.Add(TItem,TMainQty...) on Form1
it shows input array is longer than the number of columns in this table
and when I create a new column it says the column already exists.
My advice would be to separate your data from the way that the data is displayed. Apart from that this makes it easier to unit test your data handling, it gives the displayer of the data the freedom to change how this data is being displayed.
In WPF this separation of model and view is almost forced, in Winforms you really have to pay attention otherwise you mix your data handling with the way that it is displayed, making it hard to change this.
In your case: should Form1 care about how the data is displayed in Form2, should it know that Form2 uses a DataGridView? Or should Form1 only care about what data is displayed in Form2, not in what format?
A proper interface with Form2 would be, that other Forms tell what data should be displayed, and if the data can be changed, that the other Form can ask afterwards the value of the data. Something like this:
private void ShowForm2()
{
var dataToShow = this.FetchDataToShow();
using (var dlg = new Form2())
{
dlg.Data = dataToShow;
var dlgResult = dlg.ShowDialog(this);
if (dlgResult == DialogResult.OK)
{
var dataToProcess = dlg.Data;
this.ProcessData(dataToProcess);
}
}
}
This way, you only tell Form2 what data to show, other forms don't really care about how Form2 shows its data. This gives Form2 the freedom to change how the data is displayed. Every user of this Form will have the same human interface.
By the way: did you notice that I also separated where Form1 gets the data for Form2 from and where it stores the results? This procedure also does not care about how the data is displayed in Form1, and gives you the freedom to change Form1, without having to change this procedure.
Use Databinding
It is usually way easier to use DataBinding to handle the rows in a DataGridView than to access the rows and the cells of the DataGridView directly.
To use databinding, your columns need to know which property of your Class should be displayed in this column. This is usually done in visual studio designer.
In your case, it seems that the DataGridView of Form2 needs to show ItemPurchaseDatas: every Row in the DataGridView will show several properties of one ItemPurchaseData. Using visual studio designer you will have added columns, and in every column you select the name of the property that needs to be displayed in that column:
DataGridView dataGridView1 = new DataGridView();
DataGridViewColumn columnName = new DataGridViewColumn();
columName.HeaderText = "Item Name";
columName.DataPropertyName = nameof(ItemPurchaseData.Name);
...
DataGridViewColumn columnPrice = new DataGridViewColumn();
columnPrice.HeaderText = "Price";
columnPrice.DataPropertyName = nameof(ItemPurchaseData.Price);
...
We earlier saw that the dialog had a property Data, that contains the data to be shown.
The form needs a method to extract the ItemPurchaseDatas that must be shown in the DataGridView:
public IEnumerable<ItemPurchaseData> GetInitialItemPurchaseDatas()
{
// TODO: use property Data to extract the ItemPurchaseDatas that must be shown
// in the DataGridView
}
Now all you have to do is on the event handler of FormLoad, get the data and put it in the DataSource of dataGridView1:
private void OnFormLoading(object sender, ...)
{
List<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas().ToList();
this.dataGridView1.DataSource = itemPurchaseDatas;
}
This is enough to show the data. However, it will be readonly: any changes that the operator makes: edits, addition of rows, removal of rows etc, are not reflected in itemPurchaseDatas. If you want that, you need an object that implements IBindingList like BindingList<T>.
If you want to know the changes that the operator made, it is usually wise to add the following methods:
private BindingList<ItemPurchaseData> DisplayedData
{
get => (BindingList<ItemPurchaseData>)this.dataGridView1.DataSource;
set => this.dataGridView1.DataSource = value;
}
Now every change that the operator makes to the displayed data: add / remove rows, change cells, etc are reflected in property DisplayedData. Again, the display of the data is separated from the data itself: If the operator changes the looks of how the data is displayed, sorting the rows, rearranging the columns has no influence on the DisplayedData.
If you regularly have to handle SelectedRows, consider to add the following properties:
private ItemPurchaseData CurrentItemPurchaseData =>
(ItemPurchaseData)this.dataGridView1.CurrentRow?.DataBoundItem;
private IEnumerable<ItemPurchaseData> SelectedItemPurchaseData =>
this.dataGridView1.DataSource.SelectedRows.Cast<DataGridViewRow>()
.Select(row => row.DataBoundItem)
.Cast<ItemPurchaseData>();
Usage: on form loading displaying the data in the DataGridView and after a button press process the edited data:
private void OnFormLoading(object sender, ...)
{
IEnumerable<ItemPurchaseData> itemPurchaseDatas = GetInitialItemPurchaseDatas();
this.DisplayedData = new BindingList<ItemPurchaseData>(itemPurchaseDatas.ToList());
}
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<ItemPurchaseData> editedData = this.DisplayedData;
// if needed: check which items are changed
this.ProcessChangedData(editedData);
}
Again: due to the separation of view and model, the code in the view are one-liners
If you only want to Display the data, it is

Can we use same datatable for pagemethod and webmethod in ASP.NET?

I am trying to create a new webpage where i need to display almost 10 different gridviews and charts.
Gridviews are binded on pageload event and charts are displayed using jquery-ajax method (using amcharts as well as highcharts) by calling WebMethod.
Initially i implemented the page in a way that after executing same set of stored procedures for gridviews(for showing grid view data) and webmethods(for drawing charts).So same sps are executed twice for this page(one for grid and another for chart).There are 10 sps required to execute for fetching the data.
So for improving the page performance i have created static datatable like this
static DataTable Report1;
and binded the gridview like this.
private void gvbindReport1()
{
try
{
Report1 = new DataTable();//refreshed datatable
DataSet ReportDS1 = objmvbl.GetReportGraph(ClientID, date_From, date_To);
if (ReportDS1.Tables.Count > 0)
{
Report1 = ReportDS1.Tables[0];//bindinding data to static datatable
}
GdReport.DataSource = Report1;
GdReport.DataBind();
}
catch (Exception ex)
{
Log.Errlog("Error Occured in gvbindReport1 : " + ex.Message.ToString());
}
}
and inside the webmethod i have used the same datatable for drawing the chart
like this
[System.Web.Services.WebMethod]
public static string GetDataReport1()
{
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row;
try
{
//processing for the data inside static datatable
if (Report1.Rows.Count > 0)
{
foreach (DataRow dr in Report1.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in Report1.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
}
}
catch (Exception ex)
{
Log.Errlog("Error Occured in GetDataReport WebMethod of Report Page : " + ex.Message.ToString());
}
return serializer.Serialize(rows);
}
with this i am able to show both grid and charts.
Now Please tell me that, is this a correct approach to deal with webmethods? i have read that webmethod have no relation to the page and all.Please Tell me the drawbacks of this method.
If this is wrong,Please suggest a better way to improve the page performance?
No, this is not the correct method. Since you have declared the DataTable as static (a static variable has application scope and cannot be instantiated) all
users will get the same result (last updated values).
You can realize this in concurrency testing.
Please check the following scenario:
Consider dtbl is the static dataTable which is initialized on the home page, and you create another instance of `datatable on the index page (both are in page load as given below).
Home
public static DataTable dtbl;
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dtbl = new DataTable();
dtbl.Columns.Add("id");
dtbl.Columns.Add("name");
for (int i = 0; i < 10; i++)
{
DataRow dr = dtbl.NewRow();
dr["id"] = i.ToString();
dr["name"] = i + 1;
dtbl.Rows.Add(dr);
}
}
}
Index page
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
home.dtbl = new DataTable();
}
}
Now put a breakpoint in each page load and run the application,
Open both the pages in separate tab.
Refresh the home page and check whether the columns are showing
Now go to the next tab (index) and refresh it (a new instance is created for dt). It will affect the data table now you will get the new data table at home also.
So if these two processes/pages are concurrently executed the latest value will get for both the pages. That's why I am saying it will realize this in concurrency testing.
You can make use of a session in this case. Consider the following code:
Home
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
dtbl = new DataTable();
dtbl.Columns.Add("id");
dtbl.Columns.Add("name");
for (int i = 0; i < 10; i++)
{
DataRow dr = dtbl.NewRow();
dr["id"] = i.ToString();
dr["name"] = i + 1;
dtbl.Rows.Add(dr);
}
if (((DataTable)Session["MyDatatable"]).Columns.Count < 0)
{
Session["MyDatatable"] = dtbl;
}
else
{
dtbl = (DataTable)Session["MyDatatable"];
}
}
}
First off, do not use, as a general rule of thumb, static variables in an web application. These act as global variables and are not instantiated with each request.
I wouldn't also suggest you using DataTables all the way up to your UI layer. Instead, work with strongly-typed objects.
Make a Model of the object you are trying to bind.
Like for example if you have a table called person that has the following fields.
Id | first_name | last_name | audit_ts
You can create an object as such:
public class Person
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
Now in a separate functions, in some class you can call your stored procedure from the database and then cast your table rows in the person table into the list of Person Object.
Now, instead of calling your stored procedure twice to get the same data, which only reduces your application's performance, what you can do is to instead of binding your grid view in your code behind at Page_Load event. Simply bind the HTML table after you make the call to your webmethod which I believe is in your code-behind. You can refer to this post regarding how to bind your HTML table with JSON object returned by your Ajax call.
This way, you are making one call to the server and to the database to use the same data to bind your table as well as your charts.
This is a good use case for the little used Cache Object Many users understand ViewState and SessionState, however the Cache object is not as widely utilized, and although the concept is very similar, it is much more flexible.
If your page is calling 10 stored procedures twice (once for your grids and a second time for your charts) then lets improve the performance by roughly 100% by eliminating the extra calls with the Cache Object
Have one call to the stored procedures in a separate method that populate your data tables cache object, which is then reused throughout your application.
private void loadReport1IntoCache()
{
//...load your data from DB into the Report1 variable here
//this line is new, and it saves your data into a global Cache variable
//with an absolute expiration of 10 minutes
Cache.Insert("Report1", Report1, null,
DateTime.Now.AddMinutes(10d),
System.Web.Caching.Cache.NoSlidingExpiration);
}
Then, when you are inside your other methods, you can use the Cache variable instead of calling stored procedures again. For example:
[System.Web.Services.WebMethod]
public static string GetDataReport1()
{
//first load the application variable before performing your other work
DataTable myCachedReport1Data = (DataTable)Cache["Report1"];
//did the Cache expire?
if (myCachedReport1Data == null)
{
//if so refresh it
loadReport1IntoCache();
//and then assign the variable the contents of the refresh and proceed
myCachedReport1Data = (DataTable)Cache["Report1"];
}
//other work here, utilizing the myCachedReport1Data variable
}
and for your grid binding:
private void gvbindReport1()
{
try
{
DataTable myCachedReport1Data = (DataTable)Cache["Report1"];
//did the Cache expire?
if (myCachedReport1Data == null)
{
//if so refresh it
loadReport1IntoCache();
//and then assign the variable the contents of the refresh
myCachedReport1Data = (DataTable)Cache["Report1"];
}
GdReport.DataSource = myCachedReport1Data ;
GdReport.DataBind();
}
catch (Exception ex)
{
Log.Errlog("Error Occured in gvbindReport1 : " + ex.Message.ToString());
}
}
Now, you will have to do a few things not mentioned here. You should consider when you want your Cache data to expire (the example given is 10 minutes). Also you should consider if you want it to be an Absolute Number of minutes (Absolute Expiry) or a number of minutes since last access (Sliding Expiry). In your case, probably absolute expiry, but only you know that. Then you will set the expiration when you are setting the variable contents.
See the Cache documentation here:
https://msdn.microsoft.com/en-us/library/6hbbsfk6.aspx
Adding Cache data:
https://msdn.microsoft.com/en-us/library/18c1wd61.aspx
Retrieving Cache data:
https://msdn.microsoft.com/en-us/library/xhy3h9f9.aspx
Looking at the code sample that you have given (and the parameters date_from and date_to that you are passing to GetReportGraph()) I assume:
you have 2 input fields where user is specifying the date range and then submitting the data (causing postback), based on which you are filtering the records and showing in grid as well as chart.
as different users would be providing different date ranges, you don't want to show the same data to all users.
as the data is filtered, its not going to have thousands of records.
I'm not sure what functionality of grid view you are using. Is it used only to show read only tabular data? If yes, you can consider the approach given by #Nabin Karki Thapa. If not check the alternate approach below:
After you have got the data table and bound it to grid view, immediately serialize it to JSON and register it as a script block (define a JS variable and assign the serialized JSON as it's value).
On the client side, while charting, instead of invoking webmethod, to get the JSON object use the JS variable that you have registered. This way you will avoid the call to web method (AJAX) and extra stored procedure call altogether.

Editing a List<T> in between two windows forms (C#)

I have a query regarding maintaining a List in between two windows forms. It's for a project where I need to create an address book.
I have chosen to maintain the contact details in the form of a List. My first windows form (form1) contains a master copy of a list AddressBook, which contains the address book.
I hardcoded 4 entries into the address book list in order to experiment and get the simple functions such as 'add' and 'edit' working.
I have a second windows form called Add, in which I can add new entries to the list. This works fine. I can add a new contact in the ADD form and this shows up in the initial form1, master form.
My problem arises in the EDIT form. I pass the AddressBook (master) list to the EDIT form. The EDIT form takes the master list and I am able to manipulate the records in that list. However when it comes to sending back the new list to the master page (form1), it does not pick it up. I am using the same code as I do in the ADD form which successfully sends back the new list. However this code does not work when sending back an edited list.
Here is my AddressBook property within form1
public List<Contact> addressBook;
public List<Contact> AddressBook
{
get { return addressBook;}
set {addressBook = value;}
}
Within EDIT:
public Edit()
{
InitializeComponent();
temp = Master.AddressBook; // temp is the temporary List I update within EDIT
}
** I then have my algorithm which successfully lets me EDIT the list temp. the list temp now has the edited list**
then when I hit the save button, I use the following code;
Master.AddressBook = temp;
All I need is for the list temp to be sent back to form1.
the code Master.AddressBook = temp; WORKS for when I add values to the list through the ADD form.
ADD FORM:
public Add()
{
InitializeComponent();
temp = Master.AddressBook;
}
**** code to add a new record into the list temp. the new record is called newRecord**********
private void btnAddClose_Click(object sender, EventArgs e)
{
stor.AddressBook = temp; // when I hit close on the form, it updates the master list AddressBook
this.Close();
}
This is all probably very poorly worded but in essence the only bit where my code fails is when I want to change my master Addressbook within form1 by replacing it with the list temp, which is the edited list from my EDIT form.
I think it's something to do with my AddressBook property. But this doesn't explain why I can replace AddressBook with a list containing new records but I can't replace it with a list containing edited records.
One way to accomplish this would be to make the list in Master static.
Master:
public static List<Contact> AddressBook { get; set; }
Note: You do not need the backing variable, and if you do want to use it, best practices would suggest that it be private. If you do decide to use it, it will also need to be static.
In the Add form, you would then gather the data to create a new Contact object and temp should, in fact, be just a Contact object.
Add Form:
private Contact newRecord = null;
public Add()
{
InitializeComponent();
newRecord = new Contact();
}
/**** code to add the user-input to the new Contact object ****/
private void btnAddClose_Click(object sender, EventArgs e)
{
Master.AddressBook.Add(newRecord);
this.Close();
}
Hope this helps.
This is where the Singleton pattern comes in handy: Implementing Singleton in C#
You will notice Application Settings uses this same patttern to allow you to globally access it without having to pass it around.
When I use a Singleton I typically make the class name like (TypeName)Manager (ex: AddressBookManager).
So the class might be something like this:
public static class AddressBookManager
{
#region Singleton
static readonly AddressBookManager instance = new AddressBookManager();
private AddressBookManager(); // prevent creating instances of this
public static AddressBookManager Current { get { return instance; } }
#endregion
AddressBook master = new AddressBook(); // the master address book
public AddressBook Master
{
get { return master; } // get the master address book
set { master = value; } // set the master address book
}
}
Then in each form you would access it like so:
var addressBook = AddressBookManager.Current.Master;
addressBook.Add(newRecord);
The problem you are experiencing with the Edit functionality probably has something to do with the way you are using temporary lists. By using a static, global list and merely adding/editing items inside of it, you don't run that problem. Since your Contact items are a class (not struct), their changes will be reflected in the list automatically since they are reference types.
The great part about Singleton classes is the ability to access them from anywhere in the project. The only caveat is that you need to be extra cautious when working with multi-threaded applications and Singleton classes.

how to avoid rebinding grid each time the control is initialized?

I've created a custom user control with a grid. I'd like to bind this grid once, and use it over and over again in my app. If I put the binding within the control, the data is retrieved as many times as I use the control. How do I bind it only once??
public ClientLookUp()
{
InitializeComponent();
vw_clientsTableAdapter.Fill(dsclientlkup.vw_clients); //This occurs as many times as I have the user control, instead of just once.
}
Well anything you put in the constructor will be executed every time you construct the object!
What about providing an Initialize method that you can call whenever you need to reload the data??
If you want to load the data only once, then load it either into a static variable or a separate class that is referenced by the control.
If you really want to use the same single grid in your control over and over, you could create a single, static grid, and have your ClientLookUp constructor add it to the right place—Panel, or whatever—whenever a new one is created.
Before you go do this road however, ask yourself if this is really what you want to do. Having the same identical grid existing in many places may cause you problems down the road. If you want to support in-grid editing, you'll find that changing one value changes the identical value in all your other grids..
EDIT
I tried getting the below code to work, but I'm not sure this approach will be possible. It seems as though the minute you try to attach the same UI element into more than one place, it gets moved out of the last place you put it; it doesn't look like you can have the same grid being in more than one place at once. This makes sense when you think about it.
Here's the code I tried. Maybe it will be of some use to you.
public UserControl1()
{
InitializeComponent();
this.Controls.Add(myStaticGridView);
myStaticGridView.Dock = DockStyle.Fill;
}
static DataGridView _staticGrid;
public DataGridView myStaticGridView
{
get
{
if (_staticGrid != null)
return _staticGrid;
_staticGrid = new DataGridView();
_staticGrid.Columns.Add("A", "A");
_staticGrid.Columns.Add("B", "B");
_staticGrid.Columns.Add("C", "C");
_staticGrid.Columns[0].DataPropertyName = "A";
_staticGrid.Columns[1].DataPropertyName = "B";
_staticGrid.Columns[2].DataPropertyName = "C";
_staticGrid.DataSource = new[] {
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
new { A = "someA", B = "someB", C = "someC"},
};
return _staticGrid;
}
}
And then loading the control like this:
private void button1_Click(object sender, EventArgs e)
{
flowLayoutPanel1.Controls.Add(new UserControl1());
}

Commit Changes after DataGridView edit using LINQ2SQL (Winforms)

Given a DataGridView that has a BindingSource set like this:
On a winform, we add a BindingSource object using the designer, called myBindingScource.
Then on the Form.Designer.cs we add this to the InitializeComponents()
myBindingSource.DataSource = typeof(MyLinq.Person); //Mylinq is the autogenerated Linq Model/Diagram
Later, in the form itself we do:
myDataView.DataSource = myBindingSource;
and then we have a method that populates the Grid…
using ( myDataContext mdc = new MyDataContext() )
{
myDataView.DataSource = from per in mdc.person
select per;
}
As an aside note, I've set up the columns in Design Time, and everything shows ok.
Since the LINQ 2 SQL is not returning an Anonymous, the "myDataView" is editable, and here comes the question…
Question is: how do I persist those changes?
There are dozens of events in the datagrid, and I'm not sure which one is more appropriate. Even if I try one of the events, I still don't know what is the code I need to execute to send those changes back to the DB in order to persist the changes.
I remember back in the ADO.NET DataSet days, you would do dataadapter.Update(dataset);
Also imagine that both the retrieve and the persist() are on a Business Layer and the method signature looks like this:
public void LoadMyDataGrid(DataGridView grid);
that method takes the form's grid and populates it using the LINQ2SQL query shown above.
Now I'd like to create a method like this:
public void SaveMyDataGrid(DataGridView grid); // or similar
The idea is that this method is not on the same class (form), many examples tend to assume that everything is together.
RowValidated event would be a good place to check to see if it's time to persist changes to the database.
this.dataGridView1.RowValidated += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_RowValidated);
private void dataGridView1_RowValidated(object sender, DataGridViewCellEventArgs e)
{
MyLinq.Person person = dataGridView1.Rows[e.RowIndex].DataBoundItem as MyLinq.Person;
if (person != null)
{
// save this person back to data access layer
}
}
After your edit:
I wouldn't pass back a datagrid instance to your service layer. I'd pass back IEnumerable<MyLinq.Person> or IList<MyLinq.Person> then iterate over the collection in your service layer, and depending on the logic performed; persist the changes to the data access layer (your database)
The 'save' method on the DataContext object is SubmitChanges().
using (MyContext c = new MyContext())
{
var q = (from p in c.People
where p.Id == 1
select p).First();
q.FirstName = "Mark";
c.SubmitChanges();
}
As Michael G mentioned, you'll need to gather the changes, and pass them back to the bll object.

Categories