¿Cómo filtrar datos usando Entity Framework de manera que DataGridView sea editable y el contexto controle los cambios?

¿Cómo filtrar datos usando Entity Framework de manera que DataGridView sea editable y el contexto controle los cambios?

Hay algunos puntos importantes que debe considerar cuando desee trabajar con el marco de la entidad en formularios de Windows en modo conectado si desea mantener el DataGridView editable incluso cuando haya aplicado un filtro.

Utilice una sola instancia de su DbContext

Use una sola instancia de su DbContext . Si crea una nueva instancia al guardar los cambios, la nueva instancia no podrá ver ningún cambio que haya realizado en otra instancia. Así que declárelo a nivel de formulario:

TestDBEntities db = new TestDBEntities();

Cargar datos - Vincular a almacenamiento local de entidades

Cuando trabaje con Entidades en modo conectado, cargue datos usando Load método de db establecido como db.Products.Load() o llamando al ToList como db.Products.ToList() .

Vincula tu BindingSource a db.Products.Local.ToBindingList() . Por lo tanto, si agrega o elimina elementos a/de la fuente de enlace, el rastreador de cambios detecta los cambios y agrega y elimina elementos por usted.

Para ver ToBindingList método de extensión agregar using System.Data.Entity; .

Si agregar está habilitado en su DataGridView y, a continuación, desactive la creación de proxy para evitar excepciones al filtrar.

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

Filtrar datos usando Linq

Para filtrar datos, use linq. No puedes usar Filter propiedad de BindingSource cuando la lista subyacente es BindingList<T>; Solo listas subyacentes que implementan el IBindingListView filtrado de soporte de interfaz.

Para aplicar el filtrado, use linq. Por ejemplo:

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

Eliminar filtro

Para eliminar el filtro, simplemente establezca la fuente de datos de su fuente de vinculación en el almacenamiento local de sus entidades nuevamente. De esta manera, agregar y eliminar funcionará cuando elimine el filtro.

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

Añadir/Quitar/Editar

Agregar funcionará solo en modo sin filtrar. Para permitir que el usuario agregue entidades, elimine el filtro.

La edición funcionará tanto en modo filtrado como sin filtrar.

Elimine obras en modo filtrado o sin filtrar. Pero si usa BindingNavigator en el modo filtrado, no puede confiar en su botón de eliminación. Para que funcione tanto para el modo filtrado como para el modo no filtrado, debe configurar DeleteItem propiedad de BindingNavigator a None y maneje su evento de clic de eliminar elemento y escriba su propio código:

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 al desechar o cerrar su formulario

Para una aplicación del mundo real, considere desechar el DbContext en disposición o cierre de formulario:

db.Dispose();

Código de muestra

A continuación se muestra un código de muestra que contiene lo que describí anteriormente.

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