2010-11-05 34 views
5

Tôi có một lớp miền giống như thế này. Tôi muốn NHibernate để lưu giá trị hiện tại của LastUpdate khi chèn/cập nhật để tôi có thể sử dụng trong truy vấn, nhưng bỏ qua nó khi truy xuất Foo từ cơ sở dữ liệu và để cho chính đối tượng tính toán lại giá trị khi tôi thực sự truy cập.Lập bản đồ một thuộc tính chỉ đọc mà không cần thiết lập bằng cách sử dụng Fluent NHibernate

public class Foo { 
    public DateTime LastUpdate { 
     get { 
      /* Complex logic to determine last update by inspecting History */ 
      return value; 
     } 
    } 
    public IEnumerable<History> History { get; set; } 
    /* etc. */ 
} 

lập bản đồ của tôi cho Foo trông như thế này:

public class FooMap : ClassMap<Foo> { 
    Map(x => x.LastUpdate) 
     .ReadOnly(); 
    HasMany(x => x.History); 
    // etc... 
} 

Tôi nghĩ rằng ReadOnly() là những gì tôi muốn thực hiện điều này, nhưng khi tôi cố gắng để tạo ra một SessionFactory tôi nhận được ngoại lệ sau đây:

Error: FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
---> NHibernate.PropertyNotFoundException: Could not find a setter for property 'LastUpdate' in class 'Foo'.

Thuộc tính không có setter vì không được đặt, chỉ đọc từ. Có phải ReadOnly() điều chính xác cần làm ở đây không? Nếu không, cái gì?

(NHibernate v3.0b1, thành thạo NHibernate v1.1)

+0

Các ReadOnly() ; chỉ các bộ trong bản đồ tạo ra xml luồng các thuộc tính insert = "false" và update = "false" của thuộc tính LastUpdate. – tolism7

Trả lời

12

ReadOnly chỉ thị thạo NHibernate không tìm kiếm các thay đổi trên thuộc tính này, điều này không tương đương với một thuộc tính chỉ đọc trong trình biên dịch-thế giới. Bất động sản của bạn không phải là chỉ đọc trong mắt NHibernate bởi vì bạn đang mong đợi nó được dân cư từ cơ sở dữ liệu của bạn. Những gì bạn cần làm là nói với NHibernate rằng nó nên truy cập giá trị của thuộc tính đó thông qua một trường riêng với cùng tên (lowercased) làm thuộc tính.

Map(x => x.LastUpdate) 
    .Access.Field(); 

Có một số lựa chọn thay thế cho việc sử dụng Field, cái nào bạn sử dụng sẽ phụ thuộc vào cách bạn đặt tên cho lĩnh vực tư nhân của bạn.

+2

Tôi không thực sự muốn thuộc tính được điền từ cơ sở dữ liệu, nó được tính động trong trình lấy. Tôi chỉ muốn nó được lưu vào cơ sở dữ liệu để tôi có thể truy vấn nó. –

+6

Nếu Nhibernate không điền vào nó, nó sẽ không biết để lưu nó bởi vì nó không có ý tưởng nếu và khi giá trị thay đổi. Cả hai giải pháp được cung cấp đều giống nhau và làm những gì bạn mô tả. NHibernate có thể truy cập các biến theo lĩnh vực, do đó bạn không cần một setter. Khi bạn truy cập getter, giá trị sẽ được tính toán động. Khi bạn cập nhật NHibernate sẽ lưu giá trị. Thực tế NHibernate populates nó từ db nên không liên quan - cho đến khi bạn truy cập bạn không biết/chăm sóc, khi bạn truy cập nó giá trị sẽ được tính toán. Nhìn vào như "khởi tạo" bởi Nhibernate nếu nó giúp. – Sisyphus

+0

@Sisyphus Giải thích đó giúp ích rất nhiều. Cảm ơn bạn. –

2

Theo như NHibernate đi, bạn có thể ánh xạ vào một lĩnh vực, tức là biến thành viên nên Nhibernate có thể truy cập các biến thành viên trực tiếp. Vì vậy, bạn có thể tạo biến thành viên như _lastUpdate có thể được ánh xạ trực tiếp. Nhibernate bây giờ sẽ có một biến để sử dụng và bạn có thể kiểm soát giá trị một cách riêng biệt trong getter của bạn vì NHibernate sẽ không còn sử dụng getter tài sản. Nó sẽ lưu giá trị, và lấy nó quá, nhưng giá trị được truy xuất không quan trọng bởi vì ngay sau khi bạn truy cập thông qua getter của bạn, bạn có thể tính toán lại nó. Ditto cho các biến riêng không có getters hoặc setters.

Trong hbm thông thường, bạn chỉ cần ánh xạ truy cập = trường. Mọi người làm nó. Rõ ràng Fluent không đơn giản. Tôi không sử dụng thạo ...

EDIT ...

tìm bất cứ mục tiêu dường như luôn luôn di chuyển để lập bản đồ các lĩnh vực ủng hộ tư nhân trong phiên bản của bạn và sử dụng ...

+1

Nó đơn giản như trong Fluent NHibernate: 'Map (x => x.LastUpdate) .Access.Field() ' –

0

Chỉ cần thêm một setter tin trống để lớp học của bạn:

 private set { } 

Tôi cũng thêm một thuộc tính và một bình luận cho tài liệu ý định của tôi (và chắc ReSharper hạnh phúc):

 [UsedImplicitly] 
     // ReSharper disable once ValueParameterNotUsed 
     private set { } 
Các vấn đề liên quan