Cách tốt nhất để kiểm tra xem đối tượng có tồn tại trong Entity Framework không?


114

Cách tốt nhất để kiểm tra xem một đối tượng có tồn tại trong cơ sở dữ liệu từ quan điểm hiệu suất hay không? Tôi đang sử dụng Entity Framework 1.0 (ASP.NET 3.5 SP1).

Câu trả lời:


228

Nếu bạn không muốn thực thi SQL trực tiếp, cách tốt nhất là sử dụng Any () . Điều này là do Any () sẽ trả về ngay sau khi nó tìm thấy một kết quả phù hợp. Một tùy chọn khác là Count () , nhưng tùy chọn này có thể cần phải kiểm tra mọi hàng trước khi trả về.

Đây là một ví dụ về cách sử dụng nó:

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

Và trong vb.net

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

Và trong VB If (context.MyEntity.Any (o => o.Id <> idToMAtch)) Thì 'Đây là một trận đấu! Kết thúc Nếu Xin lỗi, điều này không có trong thẻ mã, tôi không thể tìm ra cách thực hiện!
Kevin Morrissey

Hãy nghĩ ý bạn là o.Id <> idToMatch KHÔNG bằng một trận đấu
Colin

Điều gì sẽ xảy ra nếu tôi tìm kiếm theo tên và tôi muốn lấy ID nếu nó tồn tại?
Mihai Bratulescu

Chào. làm thế nào chúng ta có thể kiểm tra xem nó có tồn tại hay không và sau đó chọn tất cả dữ liệu của nó?
ảo

1
@barnes Nếu bạn ràng buộc Tvới một giao diện có IEnumerablevà trả về các đối tượng có chứa một Id, bạn sẽ có thể sử dụng chức năng chung của mình IsExists<T>().
Suncat2000,


5

Tôi đã phải quản lý một tình huống trong đó tỷ lệ trùng lặp được cung cấp trong các bản ghi dữ liệu mới là rất cao và hàng nghìn lệnh gọi cơ sở dữ liệu đang được thực hiện để kiểm tra các bản sao (vì vậy CPU đã gửi rất nhiều thời gian ở mức 100%). Cuối cùng, tôi quyết định giữ 100.000 bản ghi cuối cùng được lưu trong bộ nhớ. Bằng cách này, tôi có thể kiểm tra các bản sao đối với các bản ghi được lưu trong bộ nhớ cache, cực kỳ nhanh khi so sánh với truy vấn LINQ dựa trên cơ sở dữ liệu SQL và sau đó ghi bất kỳ bản ghi mới thực sự nào vào cơ sở dữ liệu (cũng như thêm chúng vào bộ nhớ cache dữ liệu, mà tôi cũng sắp xếp và cắt để giữ cho độ dài của nó có thể quản lý được).

Lưu ý rằng dữ liệu thô là một tệp CSV chứa nhiều bản ghi riêng lẻ phải được phân tích cú pháp. Các bản ghi trong mỗi tệp liên tiếp (với tốc độ khoảng 1 cứ sau 5 phút) chồng chéo lên nhau đáng kể, do đó tỷ lệ trùng lặp cao.

Tóm lại, nếu bạn có dữ liệu thô được đánh dấu thời gian đến, khá nhiều thứ, thì việc sử dụng bộ nhớ đệm có thể giúp kiểm tra sự trùng lặp bản ghi.


2
Đôi khi, các nhà phát triển của chúng tôi đưa ra kịch bản của bạn, có thể có một số khúc mắc. Tôi muốn đề nghị bạn dịch giải pháp của mình sang C # để chúng tôi và nhiều nhà phát triển sắp tới sẽ được hưởng lợi. +1. Tôi cũng rất thích giải pháp được mở rộng đến một bài đăng trên blog! :)
sangam

3

Tôi biết đây là một chủ đề rất cũ nhưng chỉ trong trường hợp ai đó như bản thân tôi cần giải pháp này nhưng trong VB.NET đây là những gì tôi đã sử dụng dựa trên các câu trả lời ở trên.

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

Tôi không biết cách sử dụng Lambda trong VB nhưng trong C # thì điều này tương đương: return! Context.Erantyees.Any (c => c.PayrollNumber == PropertyToCheck). Điều này tránh việc trả về tất cả các kết quả sau đó lặp lại trong bộ nhớ.
Colin

1
@Colin đây là một bổ sung tốt Tôi đã bỏ qua vấn đề bộ nhớ với đoạn mã trên, trong VB mã là context.Eprisees.Any (c => c.PayrollNumber <> PropertyToCheck). Bây giờ tôi đã thêm điều này vào mã của mình.
Kevin Morrissey

Kevin, tôi nghĩ bạn có thể phải quay lại và sửa mã của mình. Logic của bạn chắc chắn trả về true nếu có bất kỳ số bảng lương nào không khớp, thay vì đúng khi không có bất kỳ số bảng lương nào khớp.
Colin

@Colin xin lỗi bạn nói đúng, tôi chỉ cung cấp phiên bản VB cho ví dụ của bạn, tôi không đúng lắm về C # và nghĩ rằng == không bằng VB của tôi <>.
Kevin Morrissey

1
@KevinMorrissey Tôi nghĩ coling đang nói rằng bạn cần đặt "Không phải" trước "ngữ cảnh". kể từ khi "return Không context.Employees.Any (c => c.PayrollNumber = PropertyToCheck)" KHÔNG PHẢI LÀ (tôi lặp lại), KHÔNG giống như "return context.Employees.Any (c <> c.PayrollNumber = PropertyToCheck)" . Bạn có nhìn thấy quan điểm của tôi không? Sử dụng "return Any <>" có nghĩa là nếu bạn tìm thấy bất kỳ số nào không khớp với số này (ngay cả khi một số trùng khớp tồn tại), sẽ trả về true bất kể điều gì. Thay vào đó, việc sử dụng "Not [...]. Any =" sẽ chỉ trả về True khi nó không thể tìm thấy hàng bạn đang tìm! Bạn có thấy sự khác biệt?
Erx_VB.NExT.Coder

2

Tôi đã gặp một số rắc rối với điều này - EntityKey của tôi bao gồm ba thuộc tính (PK với 3 cột) và tôi không muốn kiểm tra từng cột vì điều đó sẽ xấu. Tôi đã nghĩ về một giải pháp hoạt động mọi lúc với mọi thực thể.

Một lý do khác cho điều này là tôi không thích bắt UpdateExceptions mỗi lần.

Một chút Reflection là cần thiết để lấy giá trị của các thuộc tính chính.

Mã được triển khai dưới dạng tiện ích mở rộng để đơn giản hóa việc sử dụng như:

context.EntityExists<MyEntityType>(item);

Hãy xem:

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
Tôi muốn thêm một nhận xét cho câu trả lời của tôi, bây giờ đã gần 9 năm. Tôi nghĩ ngày nay có nhiều giải pháp và khả năng sạch hơn nhiều so với năm 2010/2011 với Entity Framwork 4. Vì vậy, tôi khuyên bạn nên dừng bỏ phiếu từ chối câu trả lời này mà thay vào đó hãy thêm một câu trả lời mới / tốt hơn bên dưới.
Sven

Cũng xin lưu ý rằng giải pháp của tôi là giải pháp chung chung hoạt động cho nhiều thực thể với các khóa tổng hợp của các bảng / vật phẩm hiện có mà tôi không thể thay đổi. Vì vậy, thay vì luôn luôn truy vấn .Any (...) với 3 thuộc tính chính, tôi chỉ đơn giản gọi là .EntityExists ().
Sven

2

Tôi chỉ kiểm tra nếu đối tượng là null, nó hoạt động 100% cho tôi

    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

Tại sao không làm điều đó?

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

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

Điều này sẽ ném ra một ngoại lệ tham chiếu null vì FirstOrDefault () sẽ trả về null nếu nó không thể tìm thấy kết quả. Tôi đoán bạn có thể làm if (result? .Field == value) để tránh điều đó.
ToDevAndBeyond

Điều này có thể chậm không cần thiết vì nó tải thực thể. Nếu tất cả những gì bạn muốn làm là kiểm tra xem khóa có tồn tại hay không.
Douglas Gaskell

0

Cách tốt nhất để làm điều đó

Bất kể đối tượng của bạn là gì và đối với bảng nào trong cơ sở dữ liệu, điều duy nhất bạn cần có là khóa chính trong đối tượng.

Mã C #

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

Mã VB.NET

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

Tại sao hai câu trả lời gần như giống hệt nhau? Sự khác biệt là không đáng kể. Ngoài ra, đây chắc chắn không phải là cách tốt nhất để làm điều đó. Không có ý nghĩa gì khi kéo các giá trị al vào cơ sở dữ liệu chỉ để kiểm tra xem bản ghi có tồn tại hay không .
Gert Arnold
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.