简体   繁体   English

如何使用Entity Framework以DataGridView可编辑和上下文跟踪更改的方式过滤数据?

[英]How to filter data using Entity Framework in a way that DataGridView be editable and context track changes?

I'm using C# Windows Form Application to populate data from sql server database table using Entity Framework (EFWinForms) using the following code : 我正在使用C#Windows Form Application使用以下代码使用Entity Framework(EFWinForms)从sql server数据库表填充数据:

MyEntityDataModel db = new MyEntityDataModel();
MyEDS = new EntityDataSource();
MyEDS.DbContext = db;
MyDataGridView.DataSource = MyEDS;
MyDataGridView.DataMember = "MyTable";

It works fine. 它工作正常。 When user edit,add data ; 用户编辑时,添加数据; data can be saved using the following code : 可以使用以下代码保存数据:

MyEDS.SaveChanges();

I want a way to filter these data throug Entity Data source so that MyDataGridView remains editable and any update done by user in filtered data can still be Saved back to database. 我想要一种通过实体数据源过滤这些数据的方法,以便MyDataGridView保持可编辑状态,用户在过滤数据中完成的任何更新仍然可以保存回数据库。 Note: When using linq to entity to filter data it works great but it just populate a snapshot of data that can't be edited or updated by user again. 注意:当使用linq to entity过滤数据时,它工作得很好,但它只是填充了用户无法再次编辑或更新的数据快照。

There are some important points which you should consider when you want to work with entity framework in windows forms in connected mode if you want to keep the DataGridView editable even when you have applied a filter. 如果要在连接模式下使用Windows窗体中的实体框架,如果要保持DataGridView可编辑,即使应用了过滤器,也应该考虑一些重点。

Use a single instance of your DbContext 使用DbContext的单个实例

Use a single instance of your DbContext . 使用DbContext的单个实例。 If you create a new instance when saving changes, the new instance can't see any change that you made on other instance. 如果在保存更改时创建新实例,则新实例无法看到您在其他实例上所做的任何更改。 So declare it at form level: 所以在表单级别声明它:

TestDBEntities db = new TestDBEntities();

Load Data - Bind To Local Storage of Entities 加载数据 - 绑定到实体的本地存储

When you work with Entities in connected mode, load data using db.Products.Load() or db.Products.ToList() . 在连接模式下使用实体时,使用db.Products.Load()db.Products.ToList()加载数据。

Bind your BindingSource to db.Products.Local.ToBindingList() . BindingSource绑定到db.Products.Local.ToBindingList() So if you add or remove items to/from binding source, change tracker detects changes and adds and removes items for you. 因此,如果您在绑定源中添加或删除项目,更改跟踪器会检测更改并为您添加和删除项目。

To see ToBindingList extension method add using System.Data.Entity; 要查看ToBindingList扩展方法,请using System.Data.Entity;添加using System.Data.Entity; .

If adding is enabled in your DataGridView , then turn off proxy creation to prevent exceptions when filtering. 如果在DataGridView启用了添加,则关闭代理创建以防止过滤时出现异常。

db.Configuration.ProxyCreationEnabled = false;
db.Products.Load(); 
this.productsBindingSource.DataSource = db.Products.Local.ToBindingList();

Filter Data Using Linq 使用Linq过滤数据

To filter data, use linq. 要过滤数据,请使用linq。 You can not use Filter property of BindingSource when the underlying list is BindingList<T> ; 当底层列表是BindingList<T>时,您不能使用BindingSource Filter属性; Only underlying lists that implement the IBindingListView interface support filtering. 只有实现IBindingListView接口的底层列表才支持过滤。

To apply filtering use linq. 要应用过滤,请使用linq。 For example: 例如:

var filteredData = db.Products.Local.ToBindingList()
    .Where(x => x.Name.Contains(this.FilterTextBox.Text));
this.productsBindingSource.DataSource = filteredData.Count() > 0 ?
    filteredData : filteredData.ToArray();

Remove Filter 删除过滤器

To remove filter, just set the data source of your binding source to the local storage of your entities again. 要删除过滤器,只需将绑定源的数据源再次设置为实体的本地存储。 This way adding and removing will work when you remove filter. 这样,当您删除过滤器时,添加和删除将起作用。

this.productsBindingSource.DataSource = db.Products.Local.ToBindingList();

Add/Remove/Edit 添加/删除/编辑

Add will work only in unfiltered mode. 添加仅适用于未过滤模式。 To let the user add entities, remove filter. 要让用户添加实体,请删除过滤器。

Editing will work in both filtered or unfiltered mode. 编辑将在过滤或未过滤模式下工作。

Remove works in both filtered or unfiltered mode. 删除在过滤或未过滤模式下工作。 But if you use BindingNavigator in filtered mode, you can't rely on its delete button. 但是如果在过滤模式下使用BindingNavigator ,则不能依赖其删除按钮。 To make it working for both filtered mode and non-filtered mode should set DeleteItem property of BindingNavigator to None and handle its delete item click event and write your own code: 要使其适用于过滤模式和非过滤模式,应将BindingNavigator DeleteItem属性设置为None并处理其删除项单击事件并编写您自己的代码:

if (productsBindingSource.Current != null)
{
    var current = (Product)this.productsBindingSource.Current;
    this.productsBindingSource.RemoveCurrent();
    if (!string.IsNullOrEmpty(this.FilterTextBox.Text))
        db.Products.Local.Remove(current);
}

Dispose DbContext on disposal or close of your Form 处理或关闭表单时处理DbContext

For a real world application consider disposing the DbContext on disposal or close of form: 对于真实世界的应用程序,请考虑将DbContext处理为处理或关闭表单:

db.Dispose();

Sample Code 示例代码

Below is a sample code which contains what I described above. 下面是一个示例代码,其中包含我上面描述的内容。

using System.Data.Entity;
SampleDbEntities db = new SampleDbEntities();
private void Form1_Load(object sender, EventArgs e)
{
    db.Configuration.ProxyCreationEnabled = false;
    db.Products.Load();
    this.productsBindingSource.DataSource = db.Products.Local.ToBindingList();
}
private void FilterButton_Click(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(this.FilterTextBox.Text))
    {
        this.productsBindingSource.DataSource = db.Products.Local.ToBindingList();
    }
    else
    {
        var filteredData = db.Products.Local.ToBindingList()
            .Where(x => x.Name.Contains(this.FilterTextBox.Text));
        this.productsBindingSource.DataSource = filteredData.Count() > 0 ?
            filteredData : filteredData.ToArray();
    }
}
private void productBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
    this.Validate();
    productsBindingSource.EndEdit();
    db.SaveChanges();
}
private void bindingNavigatorDeleteItem_Click(object sender, EventArgs e)
{
    if (productsBindingSource.Current != null)
    {
        var current = (Product)this.productsBindingSource.Current;
        this.productsBindingSource.RemoveCurrent();
        if (!string.IsNullOrEmpty(this.FilterTextBox.Text))
            db.Products.Local.Remove(current);
    }
}

While I'm not certain of your possible usage, I generally use the filter property on a binding source to select certain records without giving up the ability to update the database. 虽然我不确定您的可能用途,但我通常在绑定源上使用filter属性来选择某些记录而不放弃更新数据库的能力。 Something like this: 像这样的东西:

        // Grab search string from SearchBox
        string strSearch = Convert.ToString(RichSearchBox.Text);

        // Apply Filter to BindingSource
        tblContactsBindingSource.Filter = "FileAs LIKE '*" + strSearch + "*'";

Then use the Binding Source as the data source for the data grid view: 然后使用Binding Source作为数据网格视图的数据源:

        // Bind DataGridView to BindingSource
        recipientGridView.DataSource = tblContactsBindingSource;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM