2009-04-23 38 views
20

Có lệnh cập nhật hàng loạt tồn tại trong NHibernate không? Theo như tôi biết nó không. Vậy cách tốt nhất để xử lý tình huống này là gì? Tôi muốn làm như sau:Cập nhật hàng loạt trong NHibernate

  1. Fetch một danh sách các đối tượng (chúng ta hãy gọi cho họ một danh sách người dùng, List<User>) từ cơ sở dữ liệu
  2. Thay đổi các thuộc tính của các đối tượng, (Users.Foreach(User=>User.Country="Antartica")
  3. Cập nhật mỗi mục lại riêng lẻ (Users.Foreach(User=>NHibernate.Session.Update(User)).
  4. Gọi Session.Flush để cập nhật cơ sở dữ liệu.

Đây có phải là cách tiếp cận tốt không? Điều này sẽ dẫn đến rất nhiều chuyến đi khứ hồi giữa mã của tôi và cơ sở dữ liệu?

Bạn nghĩ sao? Hoặc là có một giải pháp thanh lịch hơn?

+0

3: Tôi nghĩ rằng bạn không có nghĩa là cam kết, bạn có nghĩa là cập nhật. –

+0

Yup, bạn nói đúng; Ý tôi là Update. – Graviton

+3

Bạn nên xóa Bước 3 vì 'Session.Update' không" cập nhật từng mục trở lại ". Thay vào đó, NHibernate xem tất cả các thay đổi được thực hiện đối với các đối tượng và tự ghi các thay đổi vào cơ sở dữ liệu mà không cần phải nói. – yfeldblum

Trả lời

20

Bắt đầu NHibernate 3.2 công việc hàng loạt có những cải tiến mà giảm thiểu cơ sở dữ liệu khứ hồi. Thông tin thêm có thể được tìm thấy trên HunabKu blog. Dưới đây là ví dụ từ nó - những thông tin cập nhật hàng loạt làm chỉ 6 roundtrips:

using (ISession s = OpenSession()) 
using (s.BeginTransaction()) 
{ 
    for (int i = 0; i < 12; i++) 
    { 
     var user = new User {UserName = "user-" + i}; 
     var group = new Group {Name = "group-" + i}; 
     s.Save(user); 
     s.Save(group); 
     user.AddMembership(group); 
    } 
    s.Transaction.Commit(); 
} 
4

Bạn không cần phải cập nhật, và cũng không tuôn ra:

IList<User> users = session.CreateQuery (...).List<User>; 
users.Foreach(u=>u.Country="Antartica") 
session.Transaction.Commit(); 

Tôi nghĩ rằng NHibernate viết một lô cho tất cả các thay đổi.

Vấn đề là người dùng của bạn cần được tải vào bộ nhớ. Nếu nó gặp sự cố, bạn vẫn có thể sử dụng SQL nguyên gốc bằng cách sử dụng NHibernate. Nhưng cho đến khi bạn không chứng minh rằng đó là một vấn đề hiệu suất, hãy gắn bó với giải pháp tốt đẹp.

+1

Điều này phụ thuộc vào FlushMode. session.FlushMode = FlushMode.Never sẽ không lưu mà không có một lời gọi rõ ràng đến Flush(). Mã của bạn sẽ làm việc với FlushMode.Commit tuy nhiên – MPritchard

+0

@Stefan Tôi không thể nhận được cập nhật hàng loạt để làm việc ... bạn có thể vui lòng giúp http://stackoverflow.com/questions/26471952/nhibernate-executing-updates-in-batches – harishr

8

Bạn có thể đặt kích thước lô cho các bản cập nhật trong tệp cấu hình nhibernate.

<property name="hibernate.adonet.batch_size">16</property> 

Và bạn không cần gọi Session.Update (Người dùng) ở đó - chỉ cần tuôn ra hoặc cam kết giao dịch và NHibernate sẽ xử lý mọi thứ cho bạn.

EDIT: Tôi đã đi để gửi một liên kết đến các phần có liên quan của các tài liệu nhibernate nhưng trang web là xuống - here's an old post from Ayende về đề tài này:

Là để cho dù việc sử dụng NHibernate (hoặc bất kỳ ORM) đây là một cách tiếp cận tốt, nó phụ thuộc vào ngữ cảnh. Nếu bạn đang thực hiện cập nhật một lần của mỗi hàng trong một bảng lớn với một giá trị duy nhất (như đặt tất cả người dùng sang quốc gia 'Nam Cực' (là một lục địa, không phải là quốc gia bằng cách này!), Thì có thể bạn nên Nếu bạn định cập nhật nhiều bản ghi cùng một lúc với một quốc gia như là một phần của logic nghiệp vụ của bạn trong việc sử dụng chung ứng dụng của bạn, thì việc sử dụng ORM có thể là một phương pháp hợp lý hơn. Các hàng bạn đang cập nhật mỗi lần

Có lẽ tùy chọn hợp lý nhất ở đây nếu bạn không chắc chắn muốn tinh chỉnh tùy chọn batch_size trong NHibernate và xem cách hoạt động. xem xét triển khai câu lệnh UPDATE thẳng sql trong mã của bạn.

2

Không, đó không phải là cách tiếp cận tốt!

SQL gốc tốt hơn nhiều lần cho loại cập nhật này.

UPDATE USERS SET COUNTRY = 'Antartica'; 

Không thể đơn giản hơn và công cụ cơ sở dữ liệu sẽ xử lý hàng trăm lần này hiệu quả hơn hàng tại một mã Java thời gian.

+1

Ông đang sử dụng NHibernate, đó là .NET không Java :) –

+1

Tôi nhầm lẫn ở đây: nếu đối số của bạn hợp lệ thì không nên sử dụng ORM vì công cụ db sẽ luôn xử lý mã SQL nhiều lần hiệu quả hơn mã ORM ... Tôi đúng? – Graviton

+0

Ngu, tôi đã cập nhật câu trả lời của tôi để trả lời bình luận của bạn ở đó. –

39

Tôi biết tôi là muộn để đảng về vấn đề này, nhưng nghĩ bạn có thể muốn biết điều này bây giờ có thể sử dụng HQL trong NHibernate 2.1+

session.CreateQuery(@"update Users set Country = 'Antarctica'") 
.ExecuteUpdate(); 
+0

Đề xuất câu trả lời của marisks cho bất kỳ ai sử dụng NH 3.2+ – MPritchard

+1

Điều này chỉ hoạt động nếu thuộc tính cho tất cả 'Người dùng' sẽ được đặt thành cùng giá trị' Antartica'. Nhưng nếu một 'List ' được cập nhật theo lô với tất cả các hạt khác nhau, thì 'HQL' này sẽ không có tác dụng. Mặc dù nó là một giải pháp cho tình hình gương mẫu đặc biệt của OP. –

1

Bắt đầu với NHibernate 5,0 nó có thể làm cho thao tác hàng loạt sử dụng LINQ.

session.Query<Cat>() 
.Where(c => c.BodyWeight > 20) 
.Update(c => new { BodyWeight = c.BodyWeight/2 }); 

Xem Updating entities

Các vấn đề liên quan