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の場合(context.MyEntity.Any(o => o.Id <> idToMAtch))の場合、 'これは一致です!終了申し訳ありませんが、これはコードタグに含まれていません。方法がわかりませんでした。
Kevin Morrissey

o.Id <> idToMatchは一致と等しくない
Colin

名前で検索し、IDが存在する場合にIDを取得するにはどうすればよいですか?
Mihai Bratulescu 2014年

こんにちは。それが存在するかどうかを確認し、その後すべてのデータを選択するにはどうすればよいですか?
virtouso 2015

1
@barnesでTあるインターフェイスに制約し、IEnumerableそれを含むオブジェクトを返すId場合、ジェネリック関数を使用できるはずIsExists<T>()です。
Suncat2000 2018年

9

パフォーマンスの観点から、EXISTSコマンドを使用した直接SQLクエリが適切だと思います。Entity FrameworkでSQLを直接実行する方法については、こちらを参照してください:http : //blogs.microsoft.co.il/blogs/gilf/archive/2009/11/25/execute-t-sql-statements-in-entity-framework- 4.aspx


ええ、いい考えですが、以前のバージョンのエンティティフレームワークに限定されています。
フレディ

5

新しいデータレコードで提供される重複の割合が非常に高く、重複をチェックするために何千ものデータベース呼び出しが行われるシナリオを管理する必要がありました(そのため、CPUは100%で多くの時間を送信しました)。最後に、メモリにキャッシュされた最後の100,000レコードを保持することにしました。このようにして、SQLデータベースに対するLINQクエリと比べて非常に高速なキャッシュされたレコードに対して重複をチェックし、真に新しいレコードをデータベースに書き込むことができます(データキャッシュにレコードを追加することもできます)。長さを管理しやすいようにソートおよびトリミングされます)。

生データは、解析が必要な多数の個別のレコードを含むCSVファイルであったことに注意してください。連続する各ファイル(5分ごとに約1の割合で来た)のレコードはかなり重複しており、重複の割合が高くなっています。

要するに、入ってくる生データにかなり順番にタイムスタンプを付けた場合、メモリキャッシュを使用すると、レコードの重複チェックに役立つ場合があります。


2
私たちの開発者があなたのシナリオを思いつくことはよくありますが、多少のひねりがあるかもしれません。私たちと多くの次期開発者が利益を得られるように、ソリューションをC#で翻訳するようにお願いします。+1。ブログの投稿まで拡張されたソリューションが気に入っています!:)
サンガム2015

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#ではこれは同等です:!context.Employees.Any(c => c.PayrollNumber == PropertyToCheck)を返します。これにより、すべての結果が返されてメモリ内でループするのを回避できます。
コリン

1
@Colinこれは良い追加です。VBではコードはcontext.Employees.Any(c => c.PayrollNumber <> PropertyToCheck)です。これをコードに追加しました。
Kevin Morrissey

ケビン、戻ってコードを修正する必要があるかもしれません。一致する給与番号がない場合はtrueではなく、一致しない給与番号がある場合は、ロジックが確実にtrueを返します。
コリン

@Colin申し訳ありませんが、私はあなたの例にVBバージョンを提供していましたが、C#はあまり適切ではなく、==は等しくないため、私のVB <>とは考えていませんでした。
Kevin Morrissey 2013年

1
@KevinMorrissey「コンテキスト」の前に「否定」を置く必要があるとコールが言っていたと思います。"未context.Employees.Anyを返す(C => c.PayrollNumber = PropertyToCheck)は、"(Iリピート)されていない、以来、IS NOT "リターンcontext.Employees.Any(C <> c.PayrollNumber = PropertyToCheck)"と同じ。私の見解はわかりますか?「return Any <>」を使用すると、この番号に一致しないものが見つかった場合(一致するものが存在する場合でも)、何があってもtrueが返されます。代わりに、「Not [...]。Any = "を使用すると、探している行が見つからない場合にのみTrueが返されます。違いがわかりますか?
Erx_VB.NExT.Coder 2013年

2

私はこれに問題がありました-私のEntityKeyは3つのプロパティ(3列のPK)で構成されており、醜いので各列をチェックしたくありませんでした。すべてのエンティティで常に機能するソリューションについて考えました。

これのもう1つの理由は、毎回UpdateExceptionsをキャッチしたくないからです。

キープロパティの値を取得するには、少しのReflectionが必要です。

コードは、次のように使用を簡略化する拡張機能として実装されます。

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歳になりました私の回答にコメントを追加したいと思います。今日、Entity Framwork 4を使用した2010/2011よりもはるかにクリーンなソリューションと可能性があると思います。そのため、この回答の反対投票をやめ、代わりに以下の新しい/より良い回答を追加することをお勧めします。
スベン

また、私のソリューションは、変更できない既存のテーブル/エンティティの複合キーを持つ多くのエンティティに対して機能する汎用的なソリューションであったことにも注意してください。したがって、常に3つの主要なプロパティを使用して.Any(...)をクエリする代わりに、単に.EntityExists()を呼び出しました。
Sven

2

オブジェクトがnullかどうかを確認するだけで、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を返すため、これはnull参照例外をスローします。それを回避するためにif(result?.field == value)を実行できると思います。
ToDevAndBeyond、2018年

これはエンティティをロードするため、不必要に遅くなる可能性があります。あなたがしたいすべては、キーが存在するかどうかを確認することです。
Douglas Gaskell

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

なぜ2つのほぼ同じ答えですか?違いはわずかです。また、これは確かにそれを行うための最良の方法ではありません。レコードが存在するかどうかを確認するためだけにデータベースからすべての値をプルしても意味がありません。
ガートアーノルド
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.