วิธีที่ดีที่สุดในการตรวจสอบว่ามีวัตถุอยู่ใน Entity Framework หรือไม่?


คำตอบ:


228

หากคุณไม่ต้องการที่จะดำเนินการ SQL โดยตรงวิธีที่ดีที่สุดคือการใช้ใด ๆ () เนื่องจาก 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)) แล้ว 'นี่คือการจับคู่! สิ้นสุดหากขออภัยนี่ไม่ได้อยู่ในแท็กโค้ดฉันคิดไม่ออกว่าต้องทำอย่างไร!
Kevin Morrissey

คิดว่าคุณหมายถึง o.Id <> idToMatch ไม่เท่ากับการแข่งขัน
Colin

จะเกิดอะไรขึ้นถ้าฉันค้นหาด้วยชื่อและฉันต้องการได้รับ ID ถ้ามีอยู่?
Mihai Bratulescu

สวัสดี เราจะตรวจสอบได้อย่างไรว่ามีอยู่หรือไม่และหลังจากนั้นเลือกข้อมูลทั้งหมด
Virtouso

1
@barnes หากคุณ จำกัดTอินเทอร์เฟซที่เป็นIEnumerableและส่งคืนอ็อบเจ็กต์ที่มี an 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


ใช่เป็นความคิดที่ดี แต่ฉัน จำกัด เฉพาะกรอบงานเอนทิตีเวอร์ชันก่อนหน้า
Freddy

5

ฉันต้องจัดการสถานการณ์ที่เปอร์เซ็นต์ของรายการซ้ำที่ให้ไว้ในบันทึกข้อมูลใหม่นั้นสูงมากและมีการเรียกฐานข้อมูลจำนวนมากเพื่อตรวจสอบรายการที่ซ้ำกัน (ดังนั้น CPU จึงส่งเวลามากที่ 100%) ในที่สุดฉันตัดสินใจเก็บบันทึก 100,000 รายการล่าสุดไว้ในหน่วยความจำ ด้วยวิธีนี้ฉันสามารถตรวจสอบรายการที่ซ้ำกันกับระเบียนแคชซึ่งเร็วมากเมื่อเทียบกับแบบสอบถาม LINQ กับฐานข้อมูล SQL จากนั้นเขียนบันทึกใหม่ ๆ ลงในฐานข้อมูล (รวมทั้งเพิ่มลงในแคชข้อมูลซึ่งฉันก็เช่นกัน จัดเรียงและตัดแต่งเพื่อให้สามารถจัดการความยาวได้)

โปรดทราบว่าข้อมูลดิบเป็นไฟล์ CSV ที่มีระเบียนแต่ละรายการจำนวนมากที่ต้องแยกวิเคราะห์ บันทึกในแต่ละไฟล์ติดต่อกัน (ซึ่งมาในอัตราประมาณ 1 ทุก 5 นาที) ทับซ้อนกันมากดังนั้นจึงมีเปอร์เซ็นต์ที่ซ้ำกันสูง

ในระยะสั้นหากคุณมีข้อมูลดิบที่ประทับเวลาเข้ามาในลำดับค่อนข้างมากการใช้แคชหน่วยความจำอาจช่วยในการตรวจสอบการทำสำเนาเรกคอร์ด


2
หลายครั้งที่เราพัฒนาขึ้นมาพร้อมกับสถานการณ์ของคุณอาจมีการเปลี่ยนแปลงบางอย่าง ฉันต้องการขอให้คุณแปลโซลูชันของคุณในภาษา C # เพื่อให้เราและนักพัฒนาที่กำลังจะมาถึงอีกมากมายได้รับประโยชน์ +1 ฉันชอบที่โซลูชันนี้ขยายไปถึงบล็อกโพสต์ด้วย! :)
Sangam

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.Employees.Any (c => c.PayrollNumber == PropertyToCheck) วิธีนี้จะหลีกเลี่ยงการส่งคืนผลลัพธ์ทั้งหมดจากนั้นวนซ้ำในหน่วยความจำ
Colin

1
@ โคลินนี่เป็นส่วนเสริมที่ดีที่ฉันมองข้ามปัญหาหน่วยความจำด้วยรหัสข้างต้นใน VB รหัสเป็นบริบทพนักงานใด ๆ (c => c.PayrollNumber <> PropertyToCheck) ฉันได้เพิ่มสิ่งนี้ในรหัสของฉันแล้ว
Kevin Morrissey

เควินฉันคิดว่าคุณอาจต้องกลับไปแก้ไขโค้ดของคุณ ตรรกะของคุณจะกลับมาเป็นจริงอย่างแน่นอนหากมีตัวเลขเงินเดือนที่ไม่ตรงกันแทนที่จะเป็นจริงเมื่อไม่มีหมายเลขบัญชีเงินเดือนที่ตรงกัน
Colin

@ โคลินขอโทษคุณพูดถูกฉันให้เวอร์ชัน VB ให้กับตัวอย่างของคุณเท่านั้นฉันไม่ถูกต้องมาก C # และคิดว่า == ไม่เท่ากับ VB ของฉัน <>
Kevin Morrissey

1
@KevinMorrissey ฉันคิดว่า coling กำลังบอกว่าคุณต้องใส่ "Not" ไว้ข้างหน้า "บริบท" ตั้งแต่ "ไม่กลับมา context.Employees.Any (c => c.PayrollNumber = PropertyToCheck)" ไม่ได้ (ผมขอย้ำ) IS NOTเช่นเดียวกับ "กลับ context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . คุณเห็นประเด็นของฉันไหม การใช้ "return Any <>" หมายความว่าหากคุณพบสิ่งที่ไม่ตรงกับตัวเลขนี้ (แม้ว่าจะมีค่าที่ตรงกันอยู่ก็ตาม) จะส่งคืนจริงไม่ว่าจะเป็นอย่างไร แต่การใช้ "Not [... ] any =" จะส่งคืน True ก็ต่อเมื่อไม่พบแถวที่คุณกำลังมองหา! คุณเห็นความแตกต่างหรือไม่?
Erx_VB.NExT.Coder

2

ฉันมีปัญหากับสิ่งนี้ - EntityKey ของฉันประกอบด้วยสามคุณสมบัติ (PK ที่มี 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 ดังนั้นฉันขอแนะนำให้หยุดลงคะแนนคำตอบนี้ แต่เพิ่มคำตอบใหม่ / ดีกว่าด้านล่างแทน
Sven

โปรดทราบด้วยว่าโซลูชันของฉันเป็นโซลูชันทั่วไปที่ใช้ได้กับหลายเอนทิตีด้วยคีย์ผสมของตาราง / เอนทิตีที่มีอยู่ซึ่งฉันไม่สามารถเปลี่ยนแปลงได้ ดังนั้นแทนที่จะค้นหาเสมอ ๆ (... ) ที่มีคุณสมบัติหลัก 3 อย่างที่ฉันเรียกง่ายๆว่า. EntityExists ()
Sven

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 หากไม่พบผลลัพธ์ ฉันเดาว่าคุณสามารถทำ if (result? .field == value) เพื่อหลีกเลี่ยงสิ่งนั้น
ToDevAndBeyond

ซึ่งอาจช้าโดยไม่จำเป็นเนื่องจากโหลดเอนทิตี หากสิ่งที่คุณต้องการทำคือตรวจสอบว่ามีคีย์อยู่หรือไม่
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

ทำไมสองคำตอบที่เหมือนกันเกือบทั้งหมด? ความแตกต่างนั้นไม่มีนัยสำคัญ นอกจากนี้นี่ไม่ใช่วิธีที่ดีที่สุดอย่างแน่นอน มันไม่สมเหตุสมผลที่จะดึงค่าอัลจากฐานข้อมูลเพื่อตรวจสอบว่ามีเรกคอร์ดอยู่หรือไม่
Gert Arnold
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.