2014-04-07 17 views
5

Tôi gặp vấn đề với việc chọn một bộ sưu tập chuỗi và đã sao chép nó bằng ví dụ nhỏ sau đây.NHibernate truy vấn trên một bộ sưu tập chuỗi bằng cách sử dụng kết quả LINQ hoặc lỗi hoặc bộ sưu tập trống

Với SQL sau:

CREATE TABLE [Post] (
    [Id] INT  IDENTITY NOT NULL, 
    [Name] NVARCHAR(20) NOT NULL, 
    CONSTRAINT [PK_Post] PRIMARY KEY CLUSTERED ([Id]) 
) 
CREATE TABLE [Category] (
    [Id] INT  IDENTITY NOT NULL, 
    [PostId] INT NOT NULL, 
    [Name] NVARCHAR(20) NOT NULL, 
    CONSTRAINT [FK_Category_Post] FOREIGN KEY ([PostId]) REFERENCES [Post]([Id]) 
) 
INSERT INTO [Post] ([Name]) VALUES ('Post 1') 
INSERT INTO [Category] ([PostId], [Name]) VALUES (1, 'Alpha') 

Và mã (tôi đã sử dụng LINQPad):

void Main() 
{ 
    using (var sessionFactory = Fluently.Configure() 
     .Database(MsSqlConfiguration.MsSql2008.Dialect<MsSql2012Dialect>().ConnectionString(@"Data Source=(localdb)\Projects;Initial Catalog=NhTest;")) 
     .Mappings(x => { 
      x.FluentMappings.Add(typeof(PostMap)); 
     }) 
     .BuildSessionFactory()) 
    using (var session = sessionFactory.OpenSession()) 
    { 
     var post = session.Get<Post>(1); 
     Debug.Assert(post.Categories.First() == "Alpha"); 

     try { 
      var second = session.Query<Post>() 
       .Where(x => x.Id == 1) 
       .Select(x => new { 
        x.Categories, 
        x.Name, 
       }) 
       .Single(); 
     } 
     catch (Exception ex) { 
      Debug.Fail(ex.ToString()); 
     } 

     var third = session.Query<Post>() 
      .Where(x => x.Id == 1) 
      .Select(x => new { 
       x.Categories, 
       x.Name, 
      }) 
      .ToList().First(); 

     Debug.Assert(third.Categories.Count() == 1, "Category count was " + third.Categories.Count()); 
    } 
} 

// Define other methods and classes here 
class Post 
{ 
    public virtual int Id { get; protected set; } 
    public virtual string Name { get; protected set; } 
    public virtual IList<string> Categories { get; protected set; } 
} 

class PostMap : ClassMap<Post> 
{ 
    public PostMap() 
    { 
     Id(x => x.Id); 
     Map(x => x.Name); 

     HasMany(x => x.Categories) 
      .Table("Category") 
      .Element("Name") 
      .KeyColumn("PostId"); 
    } 
} 

Các đèo khẳng định đầu tiên và điều này, trong tâm trí của tôi, xác nhận bản đồ của tôi về loại vào bài.

Các truy vấn trong khối try ném một ngoại lệ

'System.Linq.EnumerableQuery`1[System.Collections.Generic.IList`1[System.String]]' cannot be converted to type 'System.Linq.IQueryable`1[System.Object[]] 

Vì vậy, tôi đã thay đổi nó vào nỗ lực thứ 3 mà bạn nhìn thấy trong các mã, gọi .ToList().First(). Truy vấn này không ném bất kỳ ngoại lệ nào nhưng danh sách danh mục được trả lại trống.

Tôi có làm gì sai không? Có kỹ thuật lập bản đồ tốt hơn để sử dụng ở đây không? Hoặc có cách giải quyết nào để truy vấn của tôi hoạt động không?

Trả lời

5

Đây là lỗi trong NHibernate. Nó sẽ cố gắng lấy dữ liệu ánh xạ lớp cho tham số kiểu Enumerable. Khi chiếu một Enumerable của một lớp ánh xạ này hoạt động hoàn hảo. Trong trường hợp này, tuy nhiên, tham số kiểu Enumerable là chuỗi. Chuỗi không có một bản đồ lớp và do đó nó được thay thế một hằng số null trong truy vấn mà sau đó gây ra các vấn đề sau này.

Để minh họa thêm này, truy vấn SQL ví dụ này sẽ là:

SELECT c.Name, p.Id, p.Name FROM Post p LEFT JOIN Category c ON p.Id = c.PostId WHERE p.Id = 1 

này sẽ trả về dữ liệu như vậy:

c.Name | p.Id | p.Name 
-------------------------- 
Cat 1 | 1  | Post A 
Cat 2 | 1  | Post A 

NHibernate sẽ sau đó, trong bộ nhớ, thực hiện một nhóm bằng hoạt động, bao gồm cả kiểm tra null, để tạo danh sách các danh mục cho mỗi giá trị duy nhất của p.Id. Nhóm hoạt động được thực hiện bằng cách sử dụng các chỉ mục cột.

Đó là những gì sẽ xảy ra. Các lỗi đã gây ra kết quả phải được biến đổi, trước khi nhóm bằng cách hoạt động, thành:

NULL | Cat 1 | 1  | Post A 
NULL | Cat 2 | 1  | Post A 

NHibernate sau đó được lọc kết quả nơi cột 0 là null, có nghĩa là không ai trong số họ sống sót.

Yêu cầu kéo chứa sửa chữa là ở đây: https://github.com/nhibernate/nhibernate-core/pull/262

1

Bạn có thể tạo CategoryMap, Category thực thể và thay đổi để:

public virtual IList<Category> Categories { get; protected set; } 

Tôi giả sử là một LINQ để hạn chế truy vấn nhibernate.

+0

Tôi thực sự muốn tránh tạo ra một lớp Category mới như có một danh sách các chuỗi phù hợp với tên miền của tôi tốt hơn. Tôi cũng đã thử điều này với QueryOver và nhận được cùng một lỗi. – Matt

1

Hãy thử thay đổi

var second = session.Query<Post>() 
    .Where(x => x.Id == 1) 
    .Select(x => new { 
     x.Categories, 
     x.Name, 
    }) 
    .Single(); 

Để ToList().Single() thay vì Single().

Tôi đã gặp vấn đề này trước đó, vấn đề là truy vấn sẽ trả về nhiều hàng sau đó bị ép buộc thành một loại ẩn danh duy nhất. Truy vấn không thành công vì kết quả trung gian chứa nhiều hàng thay vì một hàng.

+0

Đó là những gì tôi đã thực hiện trong truy vấn thứ ba trong mã mẫu của mình nhưng tôi nhận được kết quả không chính xác. – Matt

+0

Xin lỗi vì đã nhảy mà không đọc toàn bộ. Tôi đã tạo một truy vấn gần như giống hệt và nó trả về kết quả mong đợi. Bạn đã lược tả SQL được gửi đến cơ sở dữ liệu chưa? Tôi thấy rằng bạn đang sử dụng cơ sở dữ liệu cục bộ, tôi đoán là bạn không nhấn đúng cơ sở dữ liệu. –

+0

Tôi đã lược tả truy vấn có, và nó chọn giá trị đúng. Tôi đang bước qua mã nguồn NH vào lúc này, có vẻ như đang tạo ra một biến đổi phía máy khách không chính xác. – Matt

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