Der beste Weg, um zu überprüfen, ob ein Objekt in Entity Framework vorhanden ist?

114

Wie lässt sich aus Sicht der Leistung am besten überprüfen, ob ein Objekt in der Datenbank vorhanden ist? Ich verwende Entity Framework 1.0 (ASP.NET 3.5 SP1).

Freddy
quelle

Antworten:

228

Wenn Sie SQL nicht direkt ausführen möchten, verwenden Sie am besten Any () . Dies liegt daran, dass Any () zurückkehrt, sobald eine Übereinstimmung gefunden wird. Eine andere Option ist Count () , dies muss jedoch möglicherweise jede Zeile überprüfen, bevor Sie zurückkehren.

Hier ist ein Beispiel für die Verwendung:

if (context.MyEntity.Any(o => o.Id == idToMatch))
{
    // Match!
}

Und in vb.net

If context.MyEntity.Any(function(o) o.Id = idToMatch) Then
    ' Match!
End If
Alex Angas
quelle
Und in VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Dann 'Dies ist eine Übereinstimmung! Ende Wenn dies leider nicht im Code-Tag enthalten ist, konnte ich nicht herausfinden, wie es geht!
Kevin Morrissey
Denken Sie, Sie meinen o.Id <> idToMatch ist NICHT gleich einem Match
Colin
Was ist, wenn ich nach Namen suche und die ID erhalten möchte, falls vorhanden?
Mihai Bratulescu
Hallo. Wie können wir überprüfen, ob es existiert und danach alle seine Daten auswählen?
Virtouso
1
@barnes Wenn Sie sich Tauf eine Schnittstelle beschränken IEnumerableund Objekte zurückgeben, die eine enthalten Id, sollten Sie in der Lage sein, Ihre generische Funktion zu verwenden IsExists<T>().
Suncat2000
5

Ich musste ein Szenario verwalten, in dem der Prozentsatz der in den neuen Datensätzen bereitgestellten Duplikate sehr hoch war und so viele tausend Datenbankaufrufe durchgeführt wurden, um nach Duplikaten zu suchen (die CPU hat also viel Zeit mit 100% gesendet). Am Ende habe ich beschlossen, die letzten 100.000 Datensätze im Speicher zu speichern. Auf diese Weise konnte ich nach Duplikaten für die zwischengespeicherten Datensätze suchen, was im Vergleich zu einer LINQ-Abfrage für die SQL-Datenbank extrem schnell war, und dann alle wirklich neuen Datensätze in die Datenbank schreiben (sowie sie dem Datencache hinzufügen, den ich auch habe sortiert und zugeschnitten, um die Länge überschaubar zu halten).

Beachten Sie, dass die Rohdaten eine CSV-Datei waren, die viele einzelne Datensätze enthielt, die analysiert werden mussten. Die Datensätze in jeder aufeinanderfolgenden Datei (die alle 5 Minuten etwa 1 betrug) überlappten sich erheblich, daher der hohe Prozentsatz an Duplikaten.

Kurz gesagt, wenn Sie Rohdaten mit Zeitstempel eingegeben haben, kann die Verwendung eines Speichercaches bei der Überprüfung der Datensatzduplizierung hilfreich sein.

ProfNimrod
quelle
2
Oft haben wir Entwickler Ihr Szenario entwickelt, möglicherweise mit einigen Wendungen. Ich möchte Sie bitten, Ihre Lösung in C # zu übersetzen, damit wir und viele aufstrebende Entwickler davon profitieren. +1. Ich würde es lieben, wenn die Lösung auch zu einem Blog-Beitrag erweitert würde! :)
Sangam
3

Ich weiß, dass dies ein sehr alter Thread ist, aber nur für den Fall, dass jemand wie ich diese Lösung benötigt, aber in VB.NET habe ich Folgendes verwendet, basierend auf den obigen Antworten.

Private Function ValidateUniquePayroll(PropertyToCheck As String) As Boolean
    // Return true if Username is Unique
    Dim rtnValue = False
    Dim context = New CPMModel.CPMEntities
    If (context.Employees.Any()) Then ' Check if there are "any" records in the Employee table
        Dim employee = From c In context.Employees Select c.PayrollNumber ' Select just the PayrollNumber column to work with
        For Each item As Object In employee ' Loop through each employee in the Employees entity
            If (item = PropertyToCheck) Then ' Check if PayrollNumber in current row matches PropertyToCheck
                // Found a match, throw exception and return False
                rtnValue = False
                Exit For
            Else
                // No matches, return True (Unique)
                rtnValue = True
            End If
        Next
    Else
        // The is currently no employees in the person entity so return True (Unqiue)
        rtnValue = True
    End If
    Return rtnValue
End Function
Kevin Morrissey
quelle
Ich weiß nicht, wie man Lambda in VB verwendet, aber in C # ist dies äquivalent: return! Context.Employees.Any (c => c.PayrollNumber == PropertyToCheck). Dadurch wird vermieden, dass alle Ergebnisse zurückgegeben werden und dann im Speicher durchlaufen werden.
Colin
1
@Colin Dies ist eine gute Ergänzung. Ich habe das Speicherproblem mit dem obigen Code übersehen. In VB ist der Code context.Employees.Any (c => c.PayrollNumber <> PropertyToCheck). Ich habe dies jetzt zu meinem Code hinzugefügt.
Kevin Morrissey
Kevin, ich denke, Sie müssen möglicherweise zurückgehen und Ihren Code reparieren. Ihre Logik gibt mit Sicherheit true zurück, wenn es nicht übereinstimmende Abrechnungsnummern gibt, und nicht true, wenn keine übereinstimmenden Abrechnungsnummern vorhanden sind.
Colin
@Colin Entschuldigung, Sie haben Recht, ich habe nur eine VB-Version für Ihr Beispiel bereitgestellt. Ich habe nicht viel Recht auf C # und dachte, == wäre nicht gleich, daher mein VB <>.
Kevin Morrissey
1
@ KevinMorrissey Ich denke, Coling hat gesagt, dass Sie ein "Nicht" vor "Kontext" setzen müssen. da "return not context.Employees.Any (c => c.PayrollNumber = PropertyToCheck)" NICHT (ich wiederhole), IST NICHT dasselbe wie "return context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . Verstehst du meinen Standpunkt? Die Verwendung von "return Any <>" bedeutet, dass wenn Sie eine finden, die nicht mit dieser Nummer übereinstimmt (auch wenn eine übereinstimmende vorhanden ist), true zurückgegeben wird, egal was passiert. Wenn Sie stattdessen "Not [...]. Any =" verwenden, wird True nur zurückgegeben, wenn die gesuchte Zeile nicht gefunden werden kann! Sehen Sie den Unterschied?
Erx_VB.NExT.Coder
2

Ich hatte einige Probleme damit - mein EntityKey besteht aus drei Eigenschaften (PK mit 3 Spalten) und ich wollte nicht jede der Spalten überprüfen, da dies hässlich wäre. Ich dachte an eine Lösung, die jederzeit mit allen Entitäten funktioniert.

Ein weiterer Grund dafür ist, dass ich nicht jedes Mal UpdateExceptions abfangen möchte.

Ein wenig Reflexion ist erforderlich, um die Werte der Schlüsseleigenschaften zu erhalten.

Der Code wird als Erweiterung implementiert, um die Verwendung zu vereinfachen:

context.EntityExists<MyEntityType>(item);

Guck mal:

public static bool EntityExists<T>(this ObjectContext context, T entity)
        where T : EntityObject
    {
        object value;
        var entityKeyValues = new List<KeyValuePair<string, object>>();
        var objectSet = context.CreateObjectSet<T>().EntitySet;
        foreach (var member in objectSet.ElementType.KeyMembers)
        {
            var info = entity.GetType().GetProperty(member.Name);
            var tempValue = info.GetValue(entity, null);
            var pair = new KeyValuePair<string, object>(member.Name, tempValue);
            entityKeyValues.Add(pair);
        }
        var key = new EntityKey(objectSet.EntityContainer.Name + "." + objectSet.Name, entityKeyValues);
        if (context.TryGetObjectByKey(key, out value))
        {
            return value != null;
        }
        return false;
    }
Sven
quelle
1
Ich möchte meiner Antwort einen Kommentar hinzufügen, der jetzt fast 9 Jahre alt ist. Ich denke, heutzutage gibt es viel sauberere Lösungen und Möglichkeiten als 2010/2011 mit Entity Framwork 4. Daher würde ich empfehlen, diese Antwort nicht mehr abzustimmen, sondern unten eine neue / bessere Antwort hinzuzufügen.
Sven
Bitte beachten Sie auch, dass meine Lösung eine generische Lösung war, die für viele Entitäten mit zusammengesetzten Schlüsseln vorhandener Tabellen / Entitäten funktionierte, die ich nicht ändern konnte. Anstatt immer .Any (...) mit 3 Schlüsseleigenschaften abzufragen, habe ich einfach .EntityExists () aufgerufen.
Sven
2

Ich überprüfe nur, ob das Objekt null ist, es funktioniert 100% für mich

    try
    {
        var ID = Convert.ToInt32(Request.Params["ID"]);
        var Cert = (from cert in db.TblCompCertUploads where cert.CertID == ID select cert).FirstOrDefault();
        if (Cert != null)
        {
            db.TblCompCertUploads.DeleteObject(Cert);
            db.SaveChanges();
            ViewBag.Msg = "Deleted Successfully";
        }
        else
        {
            ViewBag.Msg = "Not Found !!";
        }                           
    }
    catch
    {
        ViewBag.Msg = "Something Went wrong";
    }

quelle
0

Warum nicht?

var result= ctx.table.Where(x => x.UserName == "Value").FirstOrDefault();

if(result?.field == value)
{
  // Match!
}
Matheus Miranda
quelle
Dies löst eine Nullreferenzausnahme aus, da FirstOrDefault () null zurückgibt, wenn kein Ergebnis gefunden werden kann. Ich denke, Sie könnten tun, wenn (Ergebnis? .Feld == Wert), um dies zu vermeiden.
ToDevAndBeyond
Dies kann unnötig langsam sein, da die Entität geladen wird. Wenn Sie nur überprüfen möchten, ob ein Schlüssel vorhanden ist oder nicht.
Douglas Gaskell
0

Der beste Weg, es zu tun

Unabhängig davon, was Ihr Objekt ist und für welche Tabelle in der Datenbank Sie nur den Primärschlüssel im Objekt benötigen.

C # -Code

var dbValue = EntityObject.Entry(obj).GetDatabaseValues();
if (dbValue == null)
{
   Don't exist
}

VB.NET-Code

Dim dbValue = EntityObject.Entry(obj).GetDatabaseValues()
If dbValue Is Nothing Then
   Don't exist
End If
Basilikum
quelle
Warum zwei fast identische Antworten? Der Unterschied ist unbedeutend. Auch dies ist sicherlich nicht der beste Weg, dies zu tun. Es ist nicht sinnvoll, alle Werte aus der Datenbank abzurufen, um zu überprüfen, ob ein Datensatz vorhanden ist .
Gert Arnold