Wie filtert man Daten mit Entity Framework so, dass DataGridView bearbeitbar ist und Änderungen im Kontext nachverfolgt werden?

Wie filtert man Daten mit Entity Framework so, dass DataGridView bearbeitbar ist und Änderungen im Kontext nachverfolgt werden?

Es gibt einige wichtige Punkte, die Sie beachten sollten, wenn Sie mit dem Entity Framework in Windows Forms im verbundenen Modus arbeiten möchten, wenn Sie den DataGridView beibehalten möchten editierbar, auch wenn Sie einen Filter angewendet haben.

Verwenden Sie eine einzelne Instanz Ihres DbContext

Verwenden Sie eine einzelne Instanz Ihres DbContext . Wenn Sie beim Speichern von Änderungen eine neue Instanz erstellen, kann die neue Instanz keine Änderungen sehen, die Sie an einer anderen Instanz vorgenommen haben. Deklarieren Sie es also auf Formularebene:

TestDBEntities db = new TestDBEntities();

Daten laden - An lokalen Speicher von Entitäten binden

Wenn Sie mit Entitäten im verbundenen Modus arbeiten, laden Sie Daten mit Load Methode von db set wie db.Products.Load() oder durch Aufruf von ToList wie db.Products.ToList() .

Binden Sie Ihre BindingSource bis db.Products.Local.ToBindingList() . Wenn Sie also Elemente zu/von der Bindungsquelle hinzufügen oder entfernen, erkennt der Änderungstracker Änderungen und fügt Elemente für Sie hinzu und entfernt sie.

Um ToBindingList zu sehen Erweiterungsmethode fügen Sie using System.Data.Entity; hinzu .

Wenn das Hinzufügen in Ihrem DataGridView aktiviert ist , und deaktivieren Sie dann die Proxy-Erstellung, um Ausnahmen beim Filtern zu verhindern.

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

Daten mit Linq filtern

Verwenden Sie zum Filtern von Daten linq. Sie können Filter nicht verwenden Eigenschaft von BindingSource wenn die zugrunde liegende Liste BindingList<T> ist; Nur zugrunde liegende Listen, die den IBindingListView implementieren Schnittstellenunterstützungsfilterung.

Um Filter anzuwenden, verwenden Sie linq. Zum Beispiel:

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

Filter entfernen

Um den Filter zu entfernen, legen Sie einfach die Datenquelle Ihrer Bindungsquelle wieder auf den lokalen Speicher Ihrer Entitäten fest. Auf diese Weise funktioniert das Hinzufügen und Entfernen, wenn Sie den Filter entfernen.

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

Hinzufügen/Entfernen/Bearbeiten

Hinzufügen funktioniert nur im ungefilterten Modus. Entfernen Sie den Filter, damit der Benutzer Entitäten hinzufügen kann.

Die Bearbeitung funktioniert sowohl im gefilterten als auch im ungefilterten Modus.

Entfernen funktioniert sowohl im gefilterten als auch im ungefilterten Modus. Aber wenn Sie BindingNavigator verwenden Im gefilterten Modus können Sie sich nicht auf die Schaltfläche zum Löschen verlassen. Damit es sowohl im gefilterten als auch im nicht gefilterten Modus funktioniert, sollte DeleteItem eingestellt werden Eigentum von BindingNavigator bis None und verarbeiten Sie das Klickereignis zum Löschen von Elementen und schreiben Sie Ihren eigenen Code:

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

Entfernen Sie DbContext bei der Entsorgung oder beim Schließen Ihres Formulars

Für eine reale Anwendung sollten Sie den DbContext entsorgen bei Entsorgung oder Abschluss des Formulars:

db.Dispose();

Beispielcode

Unten ist ein Beispielcode, der das enthält, was ich oben beschrieben habe.

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