Найкращий спосіб перевірити, чи існує об'єкт в Entity Framework?


114

Який найкращий спосіб перевірити, чи існує об’єкт у базі даних з точки зору продуктивності? Я використовую Entity Framework 1.0 (ASP.NET 3.5 SP1).

Відповіді:


228

Якщо ви не хочете безпосередньо виконувати SQL, найкращим способом є використання Any () . Це тому, що Any () повернеться, як тільки знайде відповідність. Інший варіант - Count () , але для цього, можливо, потрібно буде перевірити кожен рядок перед поверненням.

Ось приклад того, як його використовувати:

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

І в vb.net

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

І в VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Тоді "Це збіг! Кінець Якщо Вибачте, це не в тезі коду, я не міг зрозуміти, як це зробити!
Кевін Морріссі

Подумайте, ви маєте на увазі o.Id <> idToMatch НЕ дорівнює матчу
Колін

що робити, якщо я шукаю по імені і хочу отримати ідентифікатор, якщо він існує?
Михай Братулеску

Привіт. як ми можемо перевірити, чи існує, і після цього вибрати всі його дані?
virtouso

1
@barnes Якщо ви обмежуєтесь Tінтерфейсом, який є, IEnumerableі повертаєте об'єкти, що містять Id, ви повинні мати можливість використовувати свою загальну функцію IsExists<T>().
Suncat2000

9

З точки зору продуктивності, я гадаю, що прямий запит SQL за допомогою команди EXISTS був би доречним. Дивіться тут, як виконати SQL безпосередньо в Entity Framework: http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/25/execute-t-sql-statements-in-entity-framework- 4.aspx


Так, гарна ідея, але обмежена попередньою версією сутності.
Фредді

5

Мені довелося керувати сценарієм, коли відсоток дублікатів, що надаються в нових записах даних, був дуже високим, і так багато тисяч дзвінків до бази даних робилися, щоб перевірити наявність дублікатів (тому процесор відправляв багато часу на 100%). Врешті-решт я вирішив зберегти в пам’яті останні 100 000 записів. Таким чином я міг перевірити наявність дублікатів у кешованих записах, що було надзвичайно швидко порівняно із запитом LINQ проти бази даних SQL, а потім записати будь-які справді нові записи в базу даних (а також додати їх до кешу даних, що я також сортують і обробляють, щоб зберегти довжину керованої)

Зауважте, що необроблені дані були файлом CSV, який містив багато окремих записів, які потрібно було розібрати. Записи у кожному послідовному файлі (який надходив зі швидкістю близько 1 кожні 5 хвилин) значно збігалися, отже, високий відсоток дублікатів.

Коротше кажучи, якщо ви ввімкнули неодноразові необроблені дані, в порядку, то використання кешу пам'яті може допомогти у перевірці дублювання записів.


2
Багато разів, коли ми розробники придумували ваш сценарій, можливо, з деякими поворотами. Я хотів би попросити перекласти ваше рішення на C #, щоб ми та багато майбутніх розробників отримали користь. +1. Я б хотів, щоб рішення розширилося і до публікації в блозі! :)
сангам

3

Я знаю, що це дуже стара тема, але просто, якщо хтось, як я, потребує цього рішення, але у VB.NET ось те, що я використав на основі наведених вище відповідей.

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 в VB, але в C # це еквівалентно: return! Context.E Employees.Any (c => c.PayrollNumber == PropertyToCheck). Це дозволяє уникнути повернення всіх результатів, а потім прокручування в пам'яті.
Колін

1
@Colin це хороше доповнення. Я не помітив проблеми пам'яті з вищевказаним кодом, у VB код - контекст.E Employees.Any (c => c.PayrollNumber <> PropertyToCheck). Зараз я додав це до свого коду.
Кевін Морріссі

Кевін, я думаю, вам, можливо, доведеться повернутися і виправити код. Ваша логіка, безумовно, повертає істину, якщо є будь-які номери оплати праці, які не відповідають, а не істинні, коли немає відповідних номерів оплати праці.
Колін

@Colin Вибачте, що ви праві, я надавав версію VB лише для вашого прикладу, я не дуже правий C # і думав, що == не дорівнює моєму VB <>.
Кевін Морріссі

1
@KevinMorrissey Я думаю, що Coling говорив, що потрібно поставити "Not" перед "контекстом". так як "повернення НЕ context.Employees.Any (з => c.PayrollNumber = PropertyToCheck)" IS NOT (я повторюся), IS NOT такий же , як "повернення context.Employees.Any (з <> c.PayrollNumber = PropertyToCheck)" . Ви бачите мою думку? Використання "return Any <>" означає, що якщо ви знайдете те, що не відповідає цьому номеру (навіть якщо відповідне існує), повернеться істинно незалежно від того. Натомість використання "Not [...]. Any =" поверне значення True лише тоді, коли він не зможе знайти потрібну рядок! Ви бачите різницю?
Erx_VB.NExT.Coder

2

У мене були проблеми з цим - мій EntityKey складається з трьох властивостей (ПК із 3 стовпцями), і я не хотів перевіряти кожен стовпчик, оскільки це було б некрасиво. Я подумав про рішення, яке весь час працює з усіма сутностями.

Ще одна причина цього - я не люблю ловити UpdateExceptions кожен раз.

Для отримання значень основних властивостей потрібно трохи рефлексії.

Код реалізований як розширення для спрощення використання як:

context.EntityExists<MyEntityType>(item);

Подивитися:

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
Я хотів би додати коментар до своєї відповіді, якій зараз майже 9 років. Я думаю, що сьогодні є набагато чіткіші рішення та можливості, ніж це було в 2010/2011 році з Entity Framwork 4. Тож я б рекомендував припинити голосування за цю відповідь, а натомість додати новий / кращий відповідь нижче.
Свен

Будь ласка, майте на увазі, що моє рішення було загальним, яке працювало для багатьох об'єктів із складеними ключами існуючих таблиць / елементів, які я не міг змінити. Отже, замість того, щоб завжди запитувати .Any (...) з 3 ключовими властивостями я просто назвав .EntityExists ().
Свен

2

Я просто перевіряю, чи об’єкт недійсний, він працює на 100% для мене

    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

Чому б не зробити цього?

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

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

Це призведе до виключення нульового посилання, оскільки FirstOrDefault () поверне null, якщо не зможе знайти результат. Я думаю, ви могли б зробити, якщо (результат? .Field == значення) уникнути цього.
ToDevAndBeyond

Це може бути надмірно повільним, оскільки воно завантажує сутність. Якщо все, що ви хочете зробити, це перевірити, чи існує ключ чи ні.
Дуглас Гаскелл

0

Найкращий спосіб це зробити

Незалежно від того, що ваш об’єкт і для якої таблиці в базі даних, єдине, що вам потрібно мати, - це первинний ключ в об'єкті.

C # код

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

Код VB.NET

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

Чому дві майже однакові відповіді? Різниця незначна. Крім того, це точно не найкращий спосіб зробити це. Немає сенсу витягувати всі значення з бази даних лише для того, щоб перевірити, чи існує запис .
Герт Арнольд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.