Il modo migliore per verificare se l'oggetto esiste in Entity Framework?


114

Qual è il modo migliore per verificare se un oggetto esiste nel database dal punto di vista delle prestazioni? Sto usando Entity Framework 1.0 (ASP.NET 3.5 SP1).

Risposte:


228

Se non vuoi eseguire SQL direttamente, il modo migliore è usare Any () . Questo perché Any () tornerà non appena trova una corrispondenza. Un'altra opzione è Count () , ma potrebbe essere necessario controllare ogni riga prima di tornare.

Ecco un esempio di come usarlo:

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

E in vb.net

If context.MyEntity.Any(function(o) o.Id = idToMatch) Then
    ' Match!
End If

E in VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Allora 'Questa è una corrispondenza! End If Sorry, questo non è nel tag del codice, non sono riuscito a capire come farlo!
Kevin Morrissey

Penso che intendi o.Id <> idToMatch NON è uguale a una corrispondenza
Colin

cosa succede se cerco per nome e voglio ottenere l'ID, se esiste?
Mihai Bratulescu

Ciao. come possiamo verificare se esiste e poi selezionare tutti i suoi dati?
virtouso

1
@barnes Se vincoli Ta un'interfaccia che è IEnumerablee restituisci oggetti che contengono un Id, dovresti essere in grado di usare la tua funzione generica IsExists<T>().
Suncat2000


5

Ho dovuto gestire uno scenario in cui la percentuale di duplicati forniti nei nuovi record di dati era molto alta e venivano effettuate così tante migliaia di chiamate al database per verificare la presenza di duplicati (quindi la CPU inviava molto tempo al 100%). Alla fine ho deciso di mantenere gli ultimi 100.000 record memorizzati nella cache. In questo modo ho potuto verificare la presenza di duplicati rispetto ai record memorizzati nella cache che era estremamente veloce rispetto a una query LINQ sul database SQL, quindi scrivere tutti i record veramente nuovi nel database (oltre ad aggiungerli alla cache dei dati, che ho anche ordinati e rifilati per mantenerne la lunghezza gestibile).

Tieni presente che i dati grezzi erano un file CSV che conteneva molti record individuali che dovevano essere analizzati. I record in ogni file consecutivo (che arrivava a una velocità di circa 1 ogni 5 minuti) si sovrapponevano notevolmente, da qui l'alta percentuale di duplicati.

In breve, se hai dati grezzi con timestamp in arrivo, praticamente in ordine, l'utilizzo di una cache di memoria potrebbe aiutare con il controllo della duplicazione dei record.


2
Molte volte noi sviluppatori inventiamo il tuo scenario, potrebbe essere con alcuni colpi di scena. Vorrei chiederti di tradurre la tua soluzione in C # in modo che noi e molti futuri sviluppatori ne trarremo vantaggio. +1. Mi piacerebbe che la soluzione si espandesse fino a un post sul blog! :)
sangam

3

So che questo è un thread molto vecchio ma solo nel caso in cui qualcuno come me abbia bisogno di questa soluzione, ma in VB.NET ecco cosa ho usato in base alle risposte sopra.

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

Non so come usare Lambda in VB ma in C # questo è equivalente: return! Context.Employees.Any (c => c.PayrollNumber == PropertyToCheck). Ciò evita di restituire tutti i risultati che vengono poi ripetuti in memoria.
Colin

1
@Colin questa è una buona aggiunta Ho trascurato il problema di memoria con il codice sopra, in VB il codice è context.Employees.Any (c => c.PayrollNumber <> PropertyToCheck). Ora l'ho aggiunto al mio codice.
Kevin Morrissey

Kevin, penso che potresti dover tornare indietro e correggere il tuo codice. La tua logica sta sicuramente restituendo vero se ci sono numeri di libro paga che non corrispondono, piuttosto che vero quando non ci sono numeri di libro paga corrispondenti.
Colin

@Colin mi dispiace che tu abbia ragione, stavo fornendo una versione VB al tuo esempio solo che non ho ragione molto C # e ho pensato che == non fosse uguale a quindi il mio VB <>.
Kevin Morrissey

1
@KevinMorrissey Penso che Coling stesse dicendo che devi mettere "Non" davanti a "contesto". poiché "return Not context.Employees.Any (c => c.PayrollNumber = PropertyToCheck)" NON È (ripeto), NON È lo stesso di "return context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . Capisci cosa intendo? Usare "return Any <>" significa che se ne trovi uno che non corrisponde a questo numero (anche se ne esiste uno corrispondente), restituirà true a prescindere da cosa. Invece, utilizzando "Not [...]. Any =" restituirà True solo quando non riesce a trovare la riga che stai cercando! Vedi la differenza?
Erx_VB.NExT.Coder

2

Ho avuto qualche problema con questo: la mia EntityKey è composta da tre proprietà (PK con 3 colonne) e non volevo controllare ciascuna delle colonne perché sarebbe brutto. Ho pensato a una soluzione che funzioni sempre con tutte le entità.

Un altro motivo è che non mi piace catturare UpdateExceptions ogni volta.

È necessario un po 'di riflessione per ottenere i valori delle proprietà chiave.

Il codice è implementato come estensione per semplificarne l'utilizzo come:

context.EntityExists<MyEntityType>(item);

Dare un'occhiata:

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

1
Vorrei aggiungere un commento alla mia risposta che ora ha quasi 9 anni. Penso che oggigiorno ci siano soluzioni e possibilità molto più pulite rispetto al 2010/2011 con Entity Framwork 4. Quindi consiglierei di smettere di votare questa risposta, ma invece di aggiungere una nuova / migliore risposta di seguito.
Sven

Tieni anche presente che la mia soluzione era generica che funzionava per molte entità con chiavi composite di tabelle / entità esistenti che non potevo modificare. Quindi, invece di interrogare sempre .Any (...) con 3 proprietà chiave, ho semplicemente chiamato .EntityExists ().
Sven

2

Controllo solo se l'oggetto è nullo, funziona al 100% per me

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

0

Perché non farlo?

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

if(result?.field == value)
{
  // Match!
}

Questo genererà un'eccezione di riferimento null perché FirstOrDefault () restituirà null se non riesce a trovare un risultato. Immagino che potresti fare se (risultato? .Field == valore) per evitarlo.
ToDevAndBeyond

Questo può essere inutilmente lento poiché carica l'entità. Se tutto quello che vuoi fare è controllare che una chiave esista o meno.
Douglas Gaskell

0

Il modo migliore per farlo

Indipendentemente da quale sia il tuo oggetto e per quale tabella nel database, l'unica cosa che devi avere è la chiave primaria nell'oggetto.

Codice C #

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

Codice VB.NET

Dim dbValue = EntityObject.Entry(obj).GetDatabaseValues()
If dbValue Is Nothing Then
   Don't exist
End If

Perché due risposte quasi identiche? La differenza è insignificante. Inoltre, questo non è certamente il modo migliore per farlo. Non ha senso estrarre i valori dal database solo per verificare se esiste un record .
Gert Arnold,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.