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

问题描述 投票:7回答:2

我正在使用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";

它工作正常。用户编辑时,添加数据;可以使用以下代码保存数据:

MyEDS.SaveChanges();

我想要一种通过实体数据源过滤这些数据的方法,以便MyDataGridView保持可编辑状态,用户在过滤数据中完成的任何更新仍然可以保存回数据库。注意:当使用linq to entity过滤数据时,它工作得很好,但它只是填充了用户无法再次编辑或更新的数据快照。

c# .net winforms entity-framework datagridview
2个回答
15
投票

如果要在连接模式下使用Windows窗体中的实体框架,如果要保持DataGridView可编辑,即使应用了过滤器,也应该考虑一些重点。

使用DbContext的单个实例

使用DbContext的单个实例。如果在保存更改时创建新实例,则新实例无法看到您在其他实例上所做的任何更改。所以在表单级别声明它:

TestDBEntities db = new TestDBEntities();

加载数据 - 绑定到实体的本地存储

在连接模式下使用实体时,使用db.Products.Load()db.Products.ToList()加载数据。

将你的BindingSource绑定到db.Products.Local.ToBindingList()。因此,如果您在绑定源中添加或删除项目,更改跟踪器会检测更改并为您添加和删除项目。

要查看ToBindingList扩展方法,请添加using System.Data.Entity;

如果在DataGridView中启用了添加,则关闭代理创建以防止过滤时出现异常。

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

使用Linq过滤数据

要过滤数据,请使用linq。当底层列表是Filter时,你不能使用BindingSourceBindingList<T>属性;只有实现IBindingListView接口的底层列表才支持过滤。

要应用过滤,请使用linq。例如:

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

删除过滤器

要删除过滤器,只需将绑定源的数据源再次设置为实体的本地存储。这样,当您删除过滤器时,添加和删除将起作用。

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

添加/删除/编辑

添加仅适用于未过滤模式。要让用户添加实体,请删除过滤器。

编辑将在过滤或未过滤模式下工作。

删除在过滤或未过滤模式下工作。但是如果你在过滤模式下使用BindingNavigator,则不能依赖它的删除按钮。要使其适用于过滤模式和非过滤模式,应将DeleteItemBindingNavigator属性设置为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);
}

处理或关闭表单时处理DbContext

对于现实世界的应用程序,考虑将DbContext处理或关闭形式:

db.Dispose();

示例代码

下面是一个示例代码,其中包含我上面描述的内容。

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);
    }
}

-1
投票

虽然我不确定您的可能用途,但我通常在绑定源上使用filter属性来选择某些记录而不放弃更新数据库的能力。像这样的东西:

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

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

然后使用Binding Source作为数据网格视图的数据源:

        // Bind DataGridView to BindingSource
        recipientGridView.DataSource = tblContactsBindingSource;
© www.soinside.com 2019 - 2024. All rights reserved.