2009-11-09 37 views
6

Tôi có hai đối tượng kinh doanh liên quan - A và B. liên kết là (A-> B) nhiều-một, với B.Id a khóa ngoại trong A (vì vậy A có A.B_id trong DB).NHibernate - truy cập ID của một đối tượng liên quan mà không cần tải toàn bộ đối tượng

Tôi đang sử dụng lazy = true và giải quyết hầu hết các vấn đề của mình, tuy nhiên trong A's ToString Tôi cũng muốn in A.B.Id, mà tôi nên có mà không cần phải đi xa hơn đến DB. nhưng truy cập A.B kích hoạt proxy, và vì điều này không có trong ngữ cảnh của một phiên mở, hãy ném một ngoại lệ.

một giải pháp dễ dàng nhưng xấu xí sẽ là có thuộc tính A.B_id. nhưng đó là một phần của những thứ chúng tôi đã cố gắng tránh ngay từ đầu. bất kỳ cách "hữu cơ" nào để thực hiện việc này? :) cảm ơn!


CẬP NHẬT: chỉ đọc về caching và Session.Get so với Session.Load. trước khi tôi chỉ mới mà một ném một ngoại lệ nếu đối tượng không tồn tại (Session.Load), và khác trả về một đối tượng null (Session.Get). sau khi đọc về bộ nhớ đệm here, rõ ràng là Session.Load trả về proxy cho đối tượng và chỉ tìm nạp nó khi một thuộc tính khác với ID được truy cập, rất giống với những gì tôi cần từ các liên kết! bây giờ tôi đã thêm id đối tượng riêng biệt (đã thêm B_Id vào A để tôi có thể truy cập nó dưới dạng A.B_Id thay vì sử dụng ABId)

+0

Tại sao bạn muốn thực hiện việc này? – Paco

+0

như tôi đã nói, chỉ để in nhật ký, v.v., trong A's ToString(). Tôi không cần các lĩnh vực khác từ B. chỉ ID. –

Trả lời

3

Vì lý do chính xác tôi đã sử dụng thuộc tính AB-ID rõ ràng cho tất cả -to-một mối quan hệ. Tôi không thấy điều này như là một giải pháp nhanh chóng và dơ bẩn vì nó cung cấp giải pháp cho vấn đề này và cũng rất linh hoạt là khu vực tiết kiệm-cập nhật tức là tôi không cần lấy từ cơ sở dữ liệu đối tượng B chỉ để gán nó cho A để tạo liên kết khi tôi có B_ID trong chuỗi truy vấn hoặc ở một nơi khác.

file ánh xạ My useually trông như thế này:

<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" /> 
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" /> 

Như bạn có thể thấy một trong 2 thuộc tính này phải được đọc chỉ để tránh việc NHibernate gửi 2 lần cột này để các cơ sở dữ liệu khi chèn hoặc updatas là xảy ra. Ở trên làm cho chỉ đọc (bằng cách sử dụng các thuộc tính insert = "false" update = "false") nhiều, nhưng thay vào đó bạn có thể chỉ đọc thuộc tính CreatorID nếu muốn.

Chỉ có nhiều người bạn không có thuộc tính trong lớp thực thể A để giữ giá trị B.ID. Cách duy nhất để có được nó là bằng cách truy cập đối tượng B sẽ kích hoạt proxy và nó sẽ kích hoạt một truy vấn đến cơ sở dữ liệu (nếu nó không được nạp trong phiên đã).

Tôi rất sẵn lòng nghe bất kỳ tùy chọn nào khác cung cấp giải pháp và cung cấp cùng loại linh hoạt.

+0

Tôi vẫn muốn điều này có thể được thực hiện chỉ bằng ABId - Tôi không thích dữ liệu trùng lặp - Tôi đã có các thuộc tính này và * xóa * chúng ... Tôi sẽ điều tra vấn đề thêm nhưng bây giờ đây là những gì tôi sẽ làm . cảm ơn! –

+0

@YonatanKarni Hoàn toàn đồng ý. Ngoài ra còn có một vấn đề hiệu suất lớn với điều này. Thêm một số lớn, n, của các thực thể 'proxy' vào một bộ sưu tập thực thể (với một kiểu sao lưu đã đặt), và nó giết hiệu suất, như n chọn, một cho mỗi proxy, được thực hiện tuần tự, như 'set.Add' Điều. – jasper

5

Nếu bạn đang sử dụng NHibernate 3.2 hoặc mới hơn, bạn có thể sử dụng đoạn mã sau để có được id của đối tượng có liên quan mà không khứ hồi khác để cơ sở dữ liệu để tải toàn bộ đối tượng:

using NHibernate.Proxy; 
... 
object id = null; 
if (obj.IsProxy()) // obj is the object you want to get its identifier. 
{ 
    var proxy = obj as INHibernateProxy; 
    if (proxy != null) 
    { 
     var li = proxy.HibernateLazyInitializer; 
     if (li != null) 
      id = li.Identifier; 
    } 
} 
1

Bạn có thể sử dụng phương pháp GetIdentifier của Phiên nhibernate:

session.GetIdentifier(obj); 
Các vấn đề liên quan