我正在使用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过滤数据时,它工作得很好,但它只是填充了用户无法再次编辑或更新的数据快照。
如果要在连接模式下使用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
时,你不能使用BindingSource
的BindingList<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
,则不能依赖它的删除按钮。要使其适用于过滤模式和非过滤模式,应将DeleteItem
的BindingNavigator
属性设置为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);
}
}
虽然我不确定您的可能用途,但我通常在绑定源上使用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;