Entity Framework'te nesnenin mevcut olup olmadığını kontrol etmenin en iyi yolu?


114

Performans açısından veritabanında bir nesnenin var olup olmadığını kontrol etmenin en iyi yolu nedir? Entity Framework 1.0 (ASP.NET 3.5 SP1) kullanıyorum.

Yanıtlar:


228

SQL'i doğrudan yürütmek istemiyorsanız, en iyi yol Any () kullanmaktır . Bunun nedeni, Any () bir eşleşme bulur bulmaz dönecek olmasıdır. Başka bir seçenek de Count () ' dır , ancak bunun geri dönmeden önce her satırı kontrol etmesi gerekebilir.

İşte nasıl kullanılacağına dair bir örnek:

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

Ve vb.net'te

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

Ve VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Sonra 'Bu bir eşleşme! End If Üzgünüz, bu kod etiketinde değil, nasıl yapılacağını bulamadım!
Kevin Morrissey

O.Id <> idToMatch bir maça eşit DEĞİL demek istediğinizi düşünün
Colin

isme göre arama yaparsam ve varsa kimliği almak istersem ne olur?
Mihai Bratulescu

Selam. var olup olmadığını nasıl kontrol edebiliriz ve bundan sonra tüm verilerini seçebiliriz?
virtouso

1
@barnes Tolan bir arabirime kısıtlarsanız ve bir IEnumerableiçeren nesneler döndürürseniz Id, genel işlevinizi kullanabilmeniz gerekir IsExists<T>().
Suncat2000


5

Yeni veri kayıtlarında sağlanan çoğaltmaların yüzdesinin çok yüksek olduğu ve yinelemeleri kontrol etmek için o kadar çok veri tabanı çağrısının yapıldığı bir senaryoyu yönetmem gerekiyordu (bu yüzden CPU çok fazla zaman gönderdi% 100). Sonunda son 100.000 kaydı hafızada tutmaya karar verdim. Bu şekilde, önbelleğe alınmış kayıtlara karşı yinelenen kayıtlar olup olmadığını kontrol edebildim, bu da SQL veritabanına yönelik bir LINQ sorgusuyla karşılaştırıldığında son derece hızlıydı ve ardından veritabanına gerçekten yeni kayıtlar yazabiliyordum (ayrıca bunları veri önbelleğine ekleyebildim. uzunluğunu yönetilebilir tutmak için sıralanmış ve kırpılmıştır).

Ham verilerin, ayrıştırılması gereken birçok ayrı kaydı içeren bir CSV dosyası olduğunu unutmayın. Her ardışık dosyadaki kayıtlar (her 5 dakikada bir yaklaşık 1 oranında gelir) önemli ölçüde örtüşüyordu, bu nedenle yineleme yüzdesi yüksek.

Kısacası, hemen hemen sırayla gelen zaman damgalı ham verileriniz varsa, bir bellek önbelleği kullanmak kayıt çoğaltma kontrolünde yardımcı olabilir.


2
Biz geliştiriciler çoğu zaman senaryonuzu buluruz, bazı katlanmalar olabilir. Sizden çözümünüzü C # dilinde çevirmenizi rica ediyorum, böylece biz ve gelecek birçok geliştirici fayda sağlayabilir. +1. Çözümün bir blog gönderisine kadar genişletilmesini de isterim! :)
sangam

3

Bunun çok eski bir iş parçacığı olduğunu biliyorum ama sadece benim gibi birinin bu çözüme ihtiyacı var ama VB.NET'te yukarıdaki cevaplara dayanarak kullandım.

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

Lambda'yı VB'de nasıl kullanacağımı bilmiyorum ama C # için bu eşdeğerdir: return! Context.Employees.Any (c => c.PayrollNumber == PropertyToCheck). Bu, tüm sonuçların geri döndürülmesini ve ardından bellekte döngü yapılmasını önler.
Colin

1
@Colin bu iyi bir eklenti Yukarıdaki kodla ilgili bellek sorununu gözden kaçırdım, VB'de kod context.Employees.Any (c => c.PayrollNumber <> PropertyToCheck). Şimdi bunu koduma ekledim.
Kevin Morrissey

Kevin, sanırım geri dönüp kodunu düzeltmen gerekebilir. Eşleşen herhangi bir bordro numarası olmadığında doğru olmak yerine, eşleşmeyen herhangi bir bordro numarası varsa mantığınız kesinlikle doğru olarak geri dönüyor.
Colin

@Colin, haklı olduğunuz için üzgünüm, örneğinize bir VB sürümü sağlıyordum, sadece C # konusunda doğru değilim ve ==, bu nedenle VB <> 'ye eşit değildi.
Kevin Morrissey

1
@KevinMorrissey Sanırım coling, "bağlam" ın önüne bir "Değil" koymanız gerektiğini söylüyordu. çünkü (Tekrar) DEĞİL "Değil context.Employees.Any (c => c.PayrollNumber = PropertyToCheck) dönüş" IS NOT aynı "return context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . benim puanımı görebiliyor musun? "Herhangi birini <> döndür" ifadesinin kullanılması, bu sayı ile eşleşmeyen herhangi bir tane bulursanız (eşleşen bir tane mevcut olsa bile), ne olursa olsun doğru döndüreceği anlamına gelir. Bunun yerine, "Değil [...]. Any =" kullanmak, yalnızca aradığınız satırı bulamadığında True döndürür! Farkı görüyor musun?
Erx_VB.NExT.Coder

2

Bununla ilgili biraz sorun yaşadım - EntityKey'im üç özellikten oluşuyor (3 sütunlu PK) ve her bir sütunu kontrol etmek istemedim çünkü bu çirkin olurdu. Her zaman tüm varlıklarla çalışan bir çözüm düşündüm.

Bunun bir başka nedeni de, her seferinde UpdateExceptions'ı yakalamaktan hoşlanmam.

Anahtar özelliklerin değerlerini elde etmek için biraz Yansıma gerekir.

Kod, aşağıdaki gibi kullanımı basitleştirmek için bir uzantı olarak uygulanır:

context.EntityExists<MyEntityType>(item);

Bir göz atın:

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
Şu anda neredeyse 9 yaşında olan cevabıma bir yorum eklemek istiyorum. Bugünlerde Varlık Çerçevesi 4 ile 2010 / 2011'de olduğundan çok daha temiz çözümler ve olasılıklar olduğunu düşünüyorum. Bu nedenle, bu yanıta oy vermeyi bırakıp bunun yerine aşağıya yeni / daha iyi bir yanıt eklemenizi tavsiye ederim.
Sven

Lütfen, benim çözümümün, değiştiremediğim mevcut tabloların / varlıkların bileşik anahtarlarıyla birçok varlık için çalışan genel bir çözüm olduğunu da unutmayın. Yani her zaman sorgulamak yerine .Any (...) 3 anahtar özelliği ile basitçe .EntityExists () adını verdim.
Sven

2

Sadece nesnenin boş olup olmadığını kontrol ediyorum, benim için% 100 çalışıyor

    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

Neden yapmıyorsun?

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

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

Bu, boş bir referans istisnası atar çünkü FirstOrDefault () bir sonuç bulamazsa null döndürür. Sanırım bundan kaçınmak için eğer (sonuç? .Field == değer) yapabilirsiniz.
ToDevAndBeyond

Bu, varlığı yüklediği için gereksiz yere yavaş olabilir. Tek yapmanız gereken bir anahtarın var olup olmadığını kontrol etmektir.
Douglas Gaskell

0

Bunu yapmanın en iyi yolu

Nesneniz ne olursa olsun ve veritabanındaki hangi tablo için ihtiyacınız olan tek şey nesnedeki birincil anahtardır.

C # Kodu

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

VB.NET Kodu

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

Neden neredeyse aynı iki cevap? Fark önemsizdir. Ayrıca, kesinlikle bunu yapmanın en iyi yolu bu değil. Yalnızca bir kaydın var olup olmadığını kontrol etmek için tüm değerleri veritabanından almak mantıklı değildir .
Gert Arnold
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.