Cara terbaik untuk memeriksa apakah objek ada di Entity Framework?


114

Apa cara terbaik untuk memeriksa apakah suatu objek ada dalam database dari sudut pandang kinerja? Saya menggunakan Entity Framework 1.0 (ASP.NET 3.5 SP1).

Jawaban:


228

Jika Anda tidak ingin mengeksekusi SQL secara langsung, cara terbaik adalah menggunakan Any () . Ini karena Any () akan kembali segera setelah menemukan kecocokan. Opsi lainnya adalah Count () , tetapi ini mungkin perlu memeriksa setiap baris sebelum kembali.

Berikut contoh cara menggunakannya:

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

Dan di vb.net

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

Dan di VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Maka 'This is a match! Akhiri Jika Maaf, ini tidak ada dalam tag kode, saya tidak tahu bagaimana melakukannya!
Kevin Morrissey

Pikirkan maksud Anda o.Id <> idToMatch TIDAK sama dengan pertandingan
Colin

bagaimana jika saya mencari berdasarkan nama dan saya ingin mendapatkan ID jika ada?
Mihai Bratulescu

Hai. bagaimana kita bisa memeriksa apakah itu ada dan setelah itu memilih semua datanya?
virtouso

1
@barnes Jika Anda membatasi Tke antarmuka yaitu IEnumerabledan mengembalikan objek yang berisi Id, Anda harus dapat menggunakan fungsi umum Anda IsExists<T>().
Suncat2000


5

Saya harus mengelola skenario di mana persentase duplikat yang diberikan dalam catatan data baru sangat tinggi, dan ribuan panggilan database dilakukan untuk memeriksa duplikat (sehingga CPU mengirimkan banyak waktu pada 100%). Pada akhirnya saya memutuskan untuk menyimpan 100.000 catatan terakhir dalam cache dalam memori. Dengan cara ini saya dapat memeriksa duplikat terhadap catatan cache yang sangat cepat jika dibandingkan dengan kueri LINQ terhadap database SQL, dan kemudian menulis catatan yang benar-benar baru ke database (serta menambahkannya ke cache data, yang saya juga diurutkan dan dipangkas agar panjangnya dapat diatur).

Perhatikan bahwa data mentah adalah file CSV yang berisi banyak catatan individu yang harus diurai. Catatan di setiap file berturut-turut (yang datang dengan kecepatan sekitar 1 setiap 5 menit) sangat tumpang tindih, karenanya tingginya persentase duplikat.

Singkatnya, jika Anda memiliki data mentah dengan stempel waktu yang masuk, cukup berurutan, maka menggunakan cache memori mungkin membantu pemeriksaan duplikasi rekaman.


2
Seringkali kami pengembang membuat skenario Anda, mungkin dengan beberapa kesulitan. Saya ingin meminta Anda untuk menerjemahkan solusi Anda dalam C # sehingga kami dan banyak pengembang yang akan datang akan mendapatkan keuntungan. +1. Saya juga ingin solusinya diperluas hingga menjadi posting blog! :)
sangam

3

Saya tahu ini adalah utas yang sangat lama tetapi hanya memetikan seseorang seperti saya membutuhkan solusi ini tetapi di VB.NET inilah yang saya gunakan berdasarkan jawaban di atas.

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

Saya tidak tahu bagaimana menggunakan Lambda di VB tetapi di C # ini setara: return! Context.Employees.Any (c => c.PayrollNumber == PropertyToCheck). Ini untuk menghindari mengembalikan semua hasil kemudian mengulang dalam memori.
Colin

1
@Colin ini adalah tambahan yang bagus Saya mengabaikan masalah memori dengan kode di atas, di VB kodenya adalah konteks.Employees.Any (c => c.PayrollNumber <> PropertyToCheck). Sekarang saya telah menambahkan ini ke kode saya.
Kevin Morrissey

Kevin, saya pikir Anda mungkin harus kembali dan memperbaiki kode Anda. Logika Anda pasti kembali benar jika ada nomor penggajian yang tidak cocok, bukan benar ketika tidak ada nomor penggajian yang cocok.
Colin

@ Colin maaf Anda benar, saya memberikan versi VB untuk contoh Anda saja saya tidak benar banyak C # dan berpikir == tidak sama dengan maka VB saya <>.
Kevin Morrissey

1
@KevinMorr Saya pikir Coling mengatakan Anda perlu meletakkan "Tidak" di depan "konteks." karena "return Tidak context.Employees.Any (c => c.PayrollNumber = PropertyToCheck)" TIDAK (saya ulangi), IS NOT sama dengan "kembali context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . Apakah Anda mengerti maksud saya? Menggunakan "return Any <>" berarti jika Anda menemukan yang tidak cocok dengan nomor ini (meskipun ada yang cocok), akan mengembalikan true apa pun yang terjadi. Sebaliknya, menggunakan "Not [...]. Any =" hanya akan mengembalikan True jika tidak dapat menemukan baris yang Anda cari! Apakah Anda melihat perbedaannya?
Erx_VB.NExT.Coder

2

Saya mengalami beberapa masalah dengan ini - EntityKey saya terdiri dari tiga properti (PK dengan 3 kolom) dan saya tidak ingin memeriksa setiap kolom karena itu akan jelek. Saya memikirkan solusi yang bekerja sepanjang waktu dengan semua entitas.

Alasan lain untuk ini adalah saya tidak suka menangkap UpdateExceptions setiap saat.

Sedikit Refleksi diperlukan untuk mendapatkan nilai properti kunci.

Kode diimplementasikan sebagai ekstensi untuk menyederhanakan penggunaan sebagai:

context.EntityExists<MyEntityType>(item);

Silahkan lihat:

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
Saya ingin menambahkan komentar pada jawaban saya yang sekarang berusia hampir 9 tahun. Saya pikir saat ini ada banyak solusi dan kemungkinan yang lebih bersih daripada yang ada di tahun 2010/2011 dengan Entity Framwork 4. Jadi saya akan merekomendasikan untuk berhenti memilih jawaban ini, tetapi tambahkan jawaban baru / lebih baik di bawah ini.
Sven

Harap juga diingat bahwa solusi saya adalah solusi umum yang berfungsi untuk banyak entitas dengan kunci komposit dari tabel / entitas yang ada yang tidak dapat saya ubah. Jadi, alih-alih selalu membuat kueri. Setiap (...) dengan 3 properti kunci, saya hanya memanggil .EntityExists ().
Sven

2

Saya hanya memeriksa apakah objeknya nol, itu berfungsi 100% untuk saya

    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

Mengapa tidak melakukannya?

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

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

Ini akan memunculkan pengecualian referensi null karena FirstOrDefault () akan mengembalikan null jika tidak dapat menemukan hasil. Saya kira Anda bisa melakukannya jika (result? .Field == nilai) untuk menghindari itu.
ToDevAndBeyond

Ini bisa menjadi lambat karena memuat entitas. Jika semua yang ingin Anda lakukan adalah memeriksa apakah ada kunci atau tidak.
Douglas Gaskell

0

Cara terbaik untuk melakukannya

Terlepas dari apa objek Anda dan untuk tabel apa dalam database, satu-satunya hal yang perlu Anda miliki adalah kunci utama dalam objek.

Kode C #

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

Kode VB.NET

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

Mengapa dua jawaban yang hampir identik? Perbedaannya tidak signifikan. Juga, ini tentunya bukan cara terbaik untuk melakukannya. Tidak masuk akal untuk menarik nilai al dari database hanya untuk memeriksa apakah ada record .
Gert Arnold
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.