I have written an article about how to use bindingsource to bind 1: N multi-table data (. NET 2.0-winform control-datagridview data binding) of the datagridview ). Here, I will overwrite it and change the bound data source from dataset to the currently popular Entity Framework ~
Sample Code download: http://download.csdn.net/source/3273686
The ms SQL express database is used. You must modify the path of the database file.
1. Data preparation:
Three tables in the northwind used by the database: MERs, orders, order details
The process of exporting entities model from the database is not mentioned here. Let's take a look at the exported EF:
Compared with the previous version of dataset, the relations attribute is used to maintain the relationship between the above three tables.
Sample Code for adding relation to Dataset:
Objdataset. relations. add ("customerorder", objdataset. tables ("customers "). columns ("customerid"), objdataset. tables ("orders "). columns ("customerid"); <br/> objdataset. relations. add ("orderdetail", objdataset. tables ("orders "). columns ("orderid"), objdataset. tables ("orderdetails "). columns ("orderid "));
In EF, if a foreign key Association has been set in dB, EF can automatically generate the object relationship, that isNavigation Properties.
Code: var order = northwind. Orders. First (). order_details can return order_details of the corresponding order
2. After preparing the data, let's take a look at the bound code:
Because EF has already completed the ORM for you (you don't need to write SQL, you don't need Adapter. Fill), you can simply use it. Because of the delayed loading feature of linq2entities, order and order_deails of each customer change are all real-time queries instead of reading and filtering at the beginning, so we keep an objectcontext instance.If objectcontext is destroyed after one binding, the binding becomes invalid.Instantiate in form_load and destroy in form_closing:
Private void form1_load (Object sender, eventargs e) <br/>{< br/> northwind = new northwndentities (); <br/> binddata (); <br/>}< br/> private void databinddemo_formclosing (Object sender, formclosingeventargs e) <br/>{< br/> If (northwind! = NULL) <br/> northwind. Dispose (); <br/>}
3. Data Binding:
1) customerbindingsource is directly bound to northwind. MERs
2) orderbindingsource bind customerbindingsource and set datamember to the navigation property of MERs -- "orders"
3) orderdetailbindingsource binds orderbindingsource and sets datamember as the navigation property of orders -- "order_details"
Private void binddata () <br/>{< br/> customerbindingsource. datasource = northwind. MERs MERS; <br/> lstcustomer. datasource = customerbindingsource; <br/> lstcustomer. valuemember = "contactname"; <br/> lstcustomer. displaymember = "contactname"; <br/> orderbindingsource. datasource = customerbindingsource; <br/> orderbindingsource. datamember = "orders"; <br/> dgvorders. datasource = orderbindingsource; <br/> dgvorders. columns ["MERs"]. visible = false; <br/> dgvorders. columns ["order_details"]. visible = false; <br/> orderdetailbindingsource. datasource = orderbindingsource; <br/> orderdetailbindingsource. datamember = "order_details"; <br/> dgvorderdetails. datasource = orderdetailbindingsource; <br/> dgvorderdetails. columns ["orders"]. visible = false; <br/> txtname. databindings. add ("text", customerbindingsource, "contactname"); <br/> txtcontacttitle. databindings. add ("text", customerbindingsource, "contacttitle"); <br/> txtaddress. databindings. add ("text", customerbindingsource, "Address"); <br/> txtcity. databindings. add ("text", customerbindingsource, "city"); <br/> txtregion. databindings. add ("text", customerbindingsource, "region"); <br/> txtpostalcode. databindings. add ("text", customerbindingsource, "postalcode"); <br/> txtphone. databindings. add ("text", customerbindingsource, "phone"); <br/> txtfax. databindings. add ("text", customerbindingsource, "fax"); <br/> txtcountry. databindings. add ("text", customerbindingsource, "country"); <br/>}
4. navigate the data. You can directly call the movexxx () method of bindingsource.
Private void btnfirst_click (Object sender, eventargs e) <br/>{< br/> customerbindingsource. movefirst (); <br/>}< br/> private void btnpre_click (Object sender, eventargs e) <br/>{< br/> customerbindingsource. moveprevious (); <br/>}< br/> private void btnnext_click (Object sender, eventargs e) <br/>{< br/> customerbindingsource. movenext (); <br/>}< br/> private void btnlast_click (Object sender, eventargs e) <br/>{< br/> customerbindingsource. movelast (); <br/>}
So far, bindingsource is used to bind EF. Run the following command to check the effect of the binding:
Next, update the database code, but it has nothing to do with bindingsource.
Because the default binding is a two-way binding, that is, any modification on the screen will affect the EF cache. You can use objectstatemanager to obtain all the modified entity (ienumerable <objectstateentry> is returned ):
VaR updated = northwind. objectstatemanager. getobjectstateentries (entitystate. modified );
The modified entity, all modified attribute names, pre-modified values, and modified values are saved in objectstateentry. Therefore, you can use the following method to output logs:
Private string log (objectstateentry entry) <br/>{< br/> var keys = ""; <br/> foreach (VAR kV in entry. entitykey. entitykeyvalues) <br/> keys + = string. format ("{0} = {1},", KV. key, KV. value); <br/> keys = keys. trimend (','); <br/> var log = string. format ("{0} ({1})/n", <br/> entry. entity. getType (). name, keys ); <br/> log + = ".............................. /n "; <br/> foreach (VAR property in entry. getmodifiedproperties () <br/>{< br/> log + = string. format ("{0 }:[ {1}]-> [{2}]", property, <br/> entry. originalvalues [property], entry. currentvalues [property]. tostring (); <br/> log + = "/N"; <br/>}< br/> return log; <br/>}
The alert information is displayed:
VaR updated = northwind. objectstatemanager. getobjectstateentries (entitystate. modified); <br/> var updateralert = "confirm to update this data:/n"; <br/> updateralert + = "-------------------------------------------/N "; <br/> foreach (var upd in updated) <br/>{< br/> updateralert + = Log (UPD ); <br/> updateralert + = "-----------------------------------------/N"; <br/>}< br/> var confirmsave = MessageBox. show (updateralert, "Confirm", messageboxbuttons. okcancel );
Look at the results: the prompt shows all the modified entity keys, modified attributes, pre-modification and post-modification values.
If you click OK, You can directly call: northwind. savechanges.
What if the user clicks cancel and does not need to modify the data? We can use the objectcontext. Refresh method. The first parameter of refresh is an enumeration:
1) refreshmode. storewins indicates that local data is discarded and DB data is accepted.
2) refreshmode. clientwins indicates that the current data is retained until savechanges () is called to update the current data to the DB.
PS: refresh is mainly used to handle concurrent errors. For example, if a piece of data you modified is modified by another client, optimisticconcurrencyexception will be thrown when savechanges () is called, in this exception, refresh is used to further process data. (Abandon or insist on updating)
Pull a little far, on EF concurrent error handling, detailed can see msdn: http://msdn.microsoft.com/zh-cn/library/bb399228.aspx
Code for calling EF update:
Private void btnupdate_click (Object sender, eventargs e) <br/>{< br/> var updated = northwind. objectstatemanager. getobjectstateentries (entitystate. modified); <br/> var updateralert = "confirm to update this data:/n"; <br/> updateralert + = "-------------------------------------------/N "; <br/> foreach (var upd in updated) <br/>{< br/> updateralert + = Log (UPD); <br/> updateralert + = "------------- ----------------------------/N "; <br/>}< br/> var confirmsave = MessageBox. show (updateralert, "Confirm", messageboxbuttons. okcancel); <br/> If (confirmsave = system. windows. forms. dialogresult. OK) <br/> {<br/> northwind. savechanges (); <br/> MessageBox. show ("all changes is saved. "); <br/>}< br/> else <br/>{< br/> var confirmreject = MessageBox. show ("reject all changes? "," Confirm ", messageboxbuttons. okcancel); <br/> If (confirmreject = system. windows. forms. dialogresult. OK) <br/> {<br/> northwind. refresh (refreshmode. storewins, northwind. customers); <br/> northwind. acceptallchanges (); <br/> MessageBox. show ("all changes is rejected. "); <br/>}< br/>}
In refresh, only northwind. MERs Mers is used. Because the three tables are already associated, You can refresh them from the top table.
Extended: the use of objectstatemanager. getobjectstateentities can also simplify the image change check process, without the need to check whether a textbox changes one by one.