Skip to main content

Post Data to an Underlying Data Source

  • 9 minutes to read

Common Tips

Data Grid (as well as other DevExpress data-aware controls) does not interact with an underlying database directly. Instead, it works with a data source that, in turn, retrieves data from a database. To push changes to an underlying database, use your data source API.

Regardless of the data binding method, changes to an underlying source should typically be posted on the following events:

ColumnView.RowUpdated
Occurs after an end user has finished modifying a row and tries to navigate to another row. RowUpdated does not fire while the editor is still active (BaseView.IsEditing), so to push changes you need to close this editor first (BaseView.CloseEditor) and call the BaseView.UpdateCurrentRow method to trigger this event manually.
ColumnView.InitNewRow | ColumnView.RowDeleted
Occurs when end users add or remove Data Grid rows.
Form.Closing
A standard WinForms event that allows you to avoid excessive updates and save all changes at once before closing an application.

In master-detail Data Grids, detail Views created at design time or in code are called Pattern Views. These Views are not connected to real data and their data-related API is not functional. Detail data is stored in Pattern View copies – Clone Views. To post changes made in detail Views, you first need to retrieve such a Clone View. To do that, call the GridView.GetDetailView method. Then you can use the CloseEditor and UpdateCurrentRow methods of this Clone View. See this help topic for more information: Working with Master-Detail Relationships in Code.

ADO.NET Data with a DataAdapter and DataSet

In traditional ADO.NET data binding, your Data Grid is bound to a Data Set, populated from an underlying data source by a Data Adapter. In this case, to post changes back to an underlying data source, call the Adapter’s Update method.

using DevExpress.XtraGrid.Views.Base;
//. . .
ColumnView view = gridControl1.FocusedView as ColumnView;
view.CloseEditor();
if(view.UpdateCurrentRow()) {
    sqlDataAdapter1.Update(myDataSet, MyTable);
}
//. . .

Note that to save changes, an Adapter must generate INSERT, UPDATE, and DELETE commands.

Entity Framework

When binding to the Entity Framework and Entity Framework Core models, the Data Grid is bound to a DbContext object. Call the SaveChanges or SaveChangesAsync methods to post changes to an underlying data source.

DXApplication.AdventureWorksDW2008R2Entities dbContext;

private void gridView1_RowUpdated(object sender, DevExpress.XtraGrid.Views.Base.RowObjectEventArgs e) {
    dbContext.SaveChanges();
}

Entity Framework Core

EF Core utilizes a different DbContext class than the one used for the standard Entity Framework.

DXApplication.AdventureWorks2014Entities dbContext;

private void gridView1_RowUpdated(object sender, DevExpress.XtraGrid.Views.Base.RowObjectEventArgs e) {
    dbContext.SaveChanges();
}

Linq to SQL

In Linq to SQL binding, a Data Grid’s data source is an object of the DataContext class. Utilize its SubmitChanges method to save changes.

System.Data.Linq.DataContext context;

private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
    context.SubmitChanges();
}

eXpress Persistent Objects (XPO)

To post changes to a data source, call the UnitOfWork.CommitChanges method. When working with sessions, the saving of persistent objects posts changes to the data source automatically.

OData

Binding to Open Data sources requires a Microsoft.OData.Client.DataServiceQuery table stored within a Microsoft.OData.Client.DataServiceContext object. To save Data Grid edits, you need to utilize the DataServiceContext API: methods like DeleteObject or UpdateObject. These methods will send corresponding HTTP queries after you call the DataServiceContext.SaveChanges method.The code for these HTTP queries must be added to a back-end application.

//server-side code
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
using WebApplication1.Models;

namespace WebApplication1.Controllers {
    public class ProductsController : ODataController {
        ProductsContext db = new ProductsContext();
        private bool ProductExists(int key) {
            return db.Products.Any(p => p.Id == key);
        }

        // . . .

        //HTTP POST
        public async Task<IHttpActionResult> Post(Product product) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }
            db.Products.Add(product);
            await db.SaveChangesAsync();
            return Created(product);
        }
        //HTTP PATCH
        public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Product> product) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }
            var entity = await db.Products.FindAsync(key);
            if (entity == null) {
                return NotFound();
            }
            product.Patch(entity);
            try {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException) {
                if (!ProductExists(key)) {
                    return NotFound();
                }
                else {
                    throw;
                }
            }
            return Updated(entity);
        }
        //HTTP PUT
        public async Task<IHttpActionResult> Put([FromODataUri] int key, Product update) {
            if (!ModelState.IsValid) {
                return BadRequest(ModelState);
            }
            if (key != update.Id) {
                return BadRequest();
            }
            db.Entry(update).State = EntityState.Modified;
            try {
                await db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException) {
                if (!ProductExists(key)) {
                    return NotFound();
                }
                else {
                    throw;
                }
            }
            return Updated(update);
        }
        //HTTP DELETE
        public async Task<IHttpActionResult> Delete([FromODataUri] int key) {
            var product = await db.Products.FindAsync(key);
            if (product == null) {
                return NotFound();
            }
            db.Products.Remove(product);
            await db.SaveChangesAsync();
            return StatusCode(HttpStatusCode.NoContent);
        }
    }
}

//client-side code
using System.Windows.Forms;
using DevExpress.XtraBars.Ribbon;
using DevExpress.XtraGrid.Views.Grid;
using Microsoft.OData.Client;

namespace DXApplication3 {
    public partial class Form1 : RibbonForm {

        DXApplication3.Default.Container container;

        public Form1() {
            InitializeComponent();
            container = new DXApplication3.Default.Container(new System.Uri("http://localhost:53684"));
            productsBindingSource.DataSource = container.Products;
            gridControl1.DataSource = productBindingSource;

            gridControl1.UseEmbeddedNavigator = true;
            gridView1.RowUpdated += GridView1_RowUpdated;
            gridView1.RowDeleting += GridView1_RowDeleting;
            gridView1.OptionsView.NewItemRowPosition = NewItemRowPosition.Top;

            //add a sample row
            var product = new WebApplication1.Models.Product() {
                Name = "Yo-yo",
                Category = "Toys",
                Price = 4.95M
            };
            container.AddObject(product);
        }

        //deleting entities from a data source
        private void GridView1_RowDeleting(object sender, DevExpress.Data.RowDeletingEventArgs e) {
            GridView view = sender as GridView;
            WebApplication1.Models.Product entity = e.Row as WebApplication1.Models.Product;
            container.DeleteObject(entity);
            container.SaveChanges();

        }

        //updating modified rows
        private void GridView1_RowUpdated(object sender, DevExpress.XtraGrid.Views.Base.RowObjectEventArgs e) {
            GridView view = sender as GridView;
            WebApplication1.Models.Product entity = view.GetFocusedRow() as WebApplication1.Models.Product;
            container.UpdateObject(entity);
            container.SaveChanges();
        }

        //Data Grid does not know an OData source is editable and both New Item Row and Data Navigator will not work
        //In this code, new rows are inserted on button clicks
        private void barButtonItem1_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) {
            WebApplication1.Models.Product entity = new WebApplication1.Models.Product();
            container.AddToProducts(entity);
            container.SaveChanges();
            //the HTTP POST will insert the entity to the data source, but the DataServiceContext will not be updated
            //in order to see a new row in Data Grid, renew your data source connection
            container = new DXApplication3.Default.Container(new System.Uri("http://localhost:53684"));
            productsBindingSource.DataSource = container.Products;
            gridControl1.RefreshDataSource();
        }
    }
}

Note that implementing in-place editing when the Data Grid is bound to a server-side data source, including Open Data sources, is not recommended. A preferable approach for this scenario is to create a substitute Data Grid source (e.g., a BindingList object populated from an OData source).

See Also