2010-10-29 37 views
5

Dự án hiện tại của tôi đang sử dụng NHibernate 3.0b1 và API NHibernate.Linq.Query<T>(). Tôi khá thông thạo LINQ, nhưng tôi hoàn toàn không có kinh nghiệm với HQL hoặc API ICriteria. Một trong các truy vấn của tôi không được API IQueryable hỗ trợ, vì vậy tôi cho rằng tôi cần phải sử dụng một trong các API trước đó - nhưng tôi không biết bắt đầu từ đâu.Làm cách nào để thể hiện truy vấn LINQ này bằng API ICriteria NHibernate?

Tôi đã thử tìm kiếm trên web một hướng dẫn "bắt đầu" tốt cho ICriteria, nhưng các ví dụ duy nhất tôi thấy là quá đơn giản để áp dụng ở đây hoặc quá tiên tiến để tôi hiểu. Nếu bất cứ ai có một số tài liệu học tập tốt để vượt qua, nó sẽ được đánh giá rất nhiều.

Trong mọi trường hợp, mô hình đối tượng tôi truy vấn chống lại ngoại hình như thế này (đơn giản hóa rất nhiều, tính chất phi liên quan bỏ qua):

class Ticket { 
    IEnumerable<TicketAction> Actions { get; set; } 
} 
abstract class TicketAction { 
    Person TakenBy { get; set; } 
    DateTime Timestamp { get; set; } 
} 
class CreateAction : TicketAction {} 
class Person { 
    string Name { get; set; } 
} 

Một Ticket có một bộ sưu tập của TicketAction mô tả lịch sử của nó. TicketAction các loại phụ bao gồm CreateAction, ReassignAction, CloseAction, v.v. Tất cả các vé có số CreateAction được thêm vào bộ sưu tập này khi được tạo.

Truy vấn LINQ này đang tìm kiếm vé được tạo bởi một người có tên đã cho.

var createdByName = "john".ToUpper(); 
var tickets = _session.Query<Ticket>() 
    .Where(t => t.Actions 
     .OfType<CreateAction>() 
     .Any(a => a.TakenBy.Name.ToUpper().Contains(createdByName)); 

Phương pháp OfType<T>() sẽ bị bỏ ra NotSupportedException. Tôi có thể làm điều này bằng cách sử dụng ICriteria thay thế không?

Trả lời

2

hãy thử một cái gì đó như thế này. Nó chưa được biên dịch, nhưng nó sẽ hoạt động miễn là IEnumerable<TicketAction> ActionsPerson TakenBy không bao giờ là rỗng. Nếu bạn đặt nó vào một danh sách trống trong trình tạo vé, điều đó sẽ giải quyết một vấn đề với các giá trị rỗng.

Nếu bạn thêm một tham chiếu đến đối tượng Ticket trong TicketAction, bạn có thể làm một cái gì đó như thế này:

ICriteria criteria = _session.CreateCriteria(typeof(CreateAction)) 
    .Add(Expression.Eq("TakenBy.Name", createdByName)); 

var actions = criteria.List<CreateAction>(); 

var results = from a in criteria.List<>() 
    select a.Ticket; 

Theo kinh nghiệm của tôi, nhibernate có rắc rối với tiêu chí khi nói đến danh sách khi danh sách là trên phía đối tượng - chẳng hạn như trường hợp của bạn. Khi đó là danh sách các giá trị ở phía đầu vào, bạn có thể sử dụng Expression.Eq. Tôi luôn phải tìm cách giới hạn giới hạn này thông qua LINQ, nơi tôi nhận được một bộ kết quả ban đầu được lọc xuống tốt nhất có thể, sau đó lọc lại với LINQ để có được những gì tôi cần.

+0

Tôi không muốn có thêm một back-tham chiếu đến một 'TicketAction' của' Ticket' nếu tôi có thể giúp nó vì điều đó sẽ giới thiệu các vấn đề khác, nhưng cảm ơn cho tip. :) –

+0

Cách khác chúng tôi xử lý các tình huống như thế này là thực sự tạo HQL trong trình tạo chuỗi. Chúng tôi đã thử sử dụng LINQ để biểu thức Nhibernate, nhưng những người quá không hỗ trợ bộ sưu tập khi bộ sưu tập là ở phía đối tượng. Thật không may, phương thức "Chứa" không dịch thông qua LINQ thành nHibernate. – Josh

+0

Tôi đã đi với đề nghị của bạn sau khi tất cả (thêm một tham chiếu đến vé trên TicketAction), nhưng tôi kết thúc với một lỗi: "NHibernate.QueryException: không thể giải quyết tài sản: TakenBy.Tên của: CreateAction " –

0

OfType được hỗ trợ. Tôi không chắc chắn ToUpper là mặc dù, nhưng như SQL bỏ qua trường hợp nó không quan trọng (miễn là bạn không phải là cũng chạy truy vấn trong bộ nhớ ...). Dưới đây là một thử nghiệm đơn vị làm việc kể từ dự án nHibernate.LINQ:

var animals = (from animal in session.Linq<Animal>() 
       where animal.Children.OfType<Mammal>().Any(m => m.Pregnant) 
       select animal).ToArray(); 
Assert.AreEqual("789", animals.Single().SerialNumber); 

Có lẽ câu hỏi của bạn nên trông giống như sau:

var animals = (from ticket in session.Linq<Ticket>() 
       where ticket.Actions.OfType<CreateAction>().Any(m => m.TakenBy.Name.Contains("john")) 
       select ticket).ToArray(); 
Các vấn đề liên quan