2008-09-19 46 views
11

Tôi muốn biết nếu có cách nào dễ dàng hơn để chèn bản ghi nếu nó chưa tồn tại trong bảng. Tôi vẫn đang cố gắng xây dựng các kỹ năng LINQ to SQL của mình.LINQ to SQL chèn-nếu-không tồn tại

Đây là những gì tôi có, nhưng có vẻ như phải có một cách dễ dàng hơn.

public static TEntity InsertIfNotExists<TEntity> 
(
    DataContext db, 
    Table<TEntity> table, 
    Func<TEntity,bool> where, 
    TEntity record 
) 
    where TEntity : class 
{ 
    TEntity existing = table.SingleOrDefault<TEntity>(where); 

    if (existing != null) 
    { 
     return existing; 
    } 
    else 
    { 
     table.InsertOnSubmit(record); 

     // Can't use table.Context.SubmitChanges() 
     // 'cause it's read-only 

     db.SubmitChanges(); 
    } 

    return record; 
} 

Trả lời

14
public static void InsertIfNotExists<TEntity> 
        (this Table<TEntity> table, 
        TEntity entity, 
        Expression<Func<TEntity,bool>> predicate) 
    where TEntity : class 
{ 
    if (!table.Any(predicate)) 
    { 
     table.InsertOnSubmit(record); 
     table.Context.SubmitChanges(); 
    } 
} 


table.InsertIfNotExists(entity, e=>e.BooleanProperty); 
+0

e => e.BooleanProperty là gì? Các thực thể không có thành viên BooleanProperty. Tôi chưa bao giờ thấy điều này trước đây ... – core

+0

Hmm, bạn sẽ nhận thấy rằng trong mã của tôi, tôi đã nói rằng table.Context.SubmitChanges() không hoạt động vì nó chỉ nhận được. Dường như tôi đã phạm sai lầm. – core

+0

e => e.BooleanProperty chỉ là một ví dụ. Nó có thể đứng cho bất kỳ biểu thức nào trả về một giá trị boolean. –

4

Đồng ý với marxidad's answer, nhưng xem ghi chú 1.

Lưu ý 1: IMHO, nó không phải là khôn ngoan để gọi db.SubmitChanges() trong một phương pháp helper, bởi vì bạn có thể phá vỡ các giao dịch ngữ cảnh. Điều này có nghĩa rằng nếu bạn gọi số InsertIfNotExists<TEntity> ở giữa một bản cập nhật phức tạp của một số thực thể, bạn sẽ lưu các thay đổi không cùng một lúc nhưng theo các bước.

Lưu ý 2: Phương pháp InsertIfNotExists<TEntity> là một phương pháp rất chung chung phù hợp với mọi trường hợp. Nếu bạn muốn chỉ cần phân biệt các đối tượng đã được nạp từ cơ sở dữ liệu từ các đối tượng đã được tạo ra từ mã, bạn có thể sử dụng phương pháp phần OnLoaded của lớp Entity như thế này:

public partial class MyEntity 
{ 
    public bool IsLoaded { get; private set; } 
    partial void OnLoaded() 
    { 
     IsLoaded = true; 
    } 
} 

Cho rằng (và lưu ý 1), sau đó chức năng InsertIfNotExists được giảm như sau:

if (!record.IsLoaded) 
    db.InsertOnSubmit(record); 
+2

Thiết kế tốt hơn có thể là phương pháp được gọi là InsertOnSubmitIfNotExists() và để thoát khỏi bảng.Context.SubmitChanges() –

4

sửa đổi nhỏ cho Mark câu trả lời:

Nếu bạn chỉ quan tâm đến việc kiểm tra nếu thực thể tồn tại bằng khóa chính của nó, câu trả lời Marke của thể được sử dụng như thế này:

public static void InsertIfNotExists<TEntity> 
        (this Table<TEntity> table 
        , TEntity entity 
        ) where TEntity : class 
    { 
     if (!table.Contains(entity)) 
     { 
      table.InsertOnSubmit(entity); 

     } 
    } 
11

Như những người khác đã chỉ ra, các giải pháp if (!Any()) { InsertOnSubmit(); } đều có điều kiện chủng tộc. Nếu bạn đi theo lộ trình đó, khi bạn gọi SubmitChanges, bạn phải tính đến việc a) một SqlException có thể được nâng lên để chèn trùng lặp hoặc b) bạn có thể có bản ghi trùng lặp trong bảng.

May mắn thay, chúng tôi có thể sử dụng cơ sở dữ liệu để tránh tình trạng cuộc đua bằng cách thực thi tính duy nhất. Đoạn mã sau giả định rằng có một khóa chính hoặc ràng buộc duy nhất trên bảng để ngăn việc chèn các bản ghi trùng lặp.

using (var db = new DataContext()) { 

    // Add the new (possibly duplicate) record to the data context here. 

    try { 
     db.SubmitChanges(); 
    } catch (SqlException ex) { 
     const int violationOfPrimaryKeyContraint = 2627; 
     const int violationOfUniqueConstraint = 2601; 
     var duplicateRecordExceptionNumbers = new [] { 
      violationOfPrimaryKeyContraint, violationOfUniqueConstraint 
     }; 
     if (!duplicateRecordExceptionNumbers.Contains(ex.Number)) { 
      throw; 
     } 
    } 
} 

Bây giờ ... mọi thứ trở nên phức tạp hơn nếu bạn phải thực hiện chèn trong giao dịch hàng loạt với các cập nhật cơ sở dữ liệu khác.