2009-06-20 34 views
21

Vấn đề: Tôi muốn chia sẻ mã giữa nhiều hội đồng. Mã chia sẻ này sẽ cần phải làm việc với các lớp được ánh xạ LINQ to SQL.LINQ to SQL - ánh xạ ngoại lệ khi sử dụng lớp cơ sở trừu tượng

Tôi đã gặp phải cùng một vấn đề được tìm thấy here, nhưng tôi cũng tìm thấy một công việc xung quanh mà tôi thấy phiền hà (Tôi sẽ không đi xa như vậy để nói "lỗi").

Tất cả các mã sau có thể được tải xuống trong this solution.

Với bảng này:

create table Users 
(
     Id int identity(1,1) not null constraint PK_Users primary key 
    , Name nvarchar(40) not null 
    , Email nvarchar(100) not null 
) 

và lập bản đồ DBML này:

<Table Name="dbo.Users" Member="Users"> 
    <Type Name="User"> 
    <Column Name="Id" Modifier="Override" Type="System.Int32" DbType="Int NOT NULL IDENTITY" IsPrimaryKey="true" IsDbGenerated="true" CanBeNull="false" /> 
    <Column Name="Name" Modifier="Override" Type="System.String" DbType="NVarChar(40) NOT NULL" CanBeNull="false" /> 
    <Column Name="Email" Modifier="Override" Type="System.String" DbType="NVarChar(100) NOT NULL" CanBeNull="false" /> 
    </Type> 
</Table> 

tôi đã tạo các lớp cơ sở sau đây trong một lắp ráp "chia sẻ":

namespace TestLinq2Sql.Shared 
{ 
    public abstract class UserBase 
    { 
     public abstract int Id { get; set; } 
     public abstract string Name { get; set; } 
     public abstract string Email { get; set; } 
    } 

    public abstract class UserBase<TUser> : UserBase where TUser : UserBase 
    { 
     public static TUser FindByName_Broken(DataContext db, string name) 
     { 
      return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name); 
     } 

     public static TUser FindByName_Works(DataContext db, string name) 
     { 
      return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name && 1 == 1); 
     } 

     public static TUser FindByNameEmail_Works(DataContext db, string name, string email) 
     { 
      return db.GetTable<TUser>().FirstOrDefault(u => u.Name == name || u.Email == email); 
     } 
    } 
} 

Các lớp này được tham chiếu trong một assembly "Main" khác, như sau:

namespace TestLinq2Sql 
{ 
    partial class User : TestLinq2Sql.Shared.UserBase<User> 
    { 

    } 
} 

Tệp DBML cũng nằm trong hội đồng "Chính".

Khi gọi User.FindByName_Broken(db, "test"), một ngoại lệ được ném:

System.InvalidOperationException: Phân loại thành viên UserBase.Name là unmapped.

Tuy nhiên, hai phương thức tĩnh cơ bản khác hoạt động.

Hơn nữa, SQL được tạo ra bằng cách gọi User.FindByName_Works(db, "test") là những gì chúng tôi đã hy vọng cho trong các cuộc gọi bị hỏng:

SELECT TOP (1) [t0].[Id], [t0].[Name], [t0].[Email] 
FROM [dbo].[Users] AS [t0] 
WHERE [t0].[Name] = @p0 
-- @p0: Input NVarChar (Size = 4; Prec = 0; Scale = 0) [test] 

Trong khi tôi sẵn sàng để sử dụng này 1 == 1 "hack" cho các truy vấn ngữ duy nhất, là có một tốt hơn cách chia sẻ mã LINQ to SQL-aware trong một assembly cơ bản/chia sẻ/lõi?

Trả lời

19

Tôi đã gặp phải vấn đề này nhiều lần trong quá khứ bởi vì chúng tôi có một kiến ​​trúc tương tự trong một khuôn khổ mà chúng tôi sử dụng trong công ty của mình.Bạn có thể nhận thấy rằng nếu bạn sử dụng kiểu truy vấn LINQ kiểu khai báo, bạn sẽ không gặp phải vấn đề này. Ví dụ: mã sau đây sẽ hoạt động:

return (from i in db.GetTable<TUser>() where i.Name = "Something").FirstOrDefault(); 

Tuy nhiên, vì chúng tôi đang sử dụng biểu thức lọc động nên chúng tôi không thể sử dụng phương pháp này. Các giải pháp thay thế là sử dụng một cái gì đó như thế này:

return db.GetTable<TUser>().Select(i => i).Where(i => i.Name == "Something").SingleOrDefault(); 

Giải pháp này giải quyết vấn đề của chúng tôi kể từ khi chúng tôi có thể tiêm một ".Chọn (i => i)" vào đầu của hầu hết các biểu thức. Điều này sẽ làm cho công cụ LINQ không nhìn vào lớp cơ sở cho ánh xạ và sẽ buộc nó phải nhìn vào lớp thực thể thực tế và tìm các ánh xạ.

Hy vọng nó giúp

+1

Nó làm một truy vấn không có bất kỳ mệnh đề where và sau đó danh sách được lọc trong bộ nhớ. Không tốt cho nhiều kết quả; – Gandarez

0

Bạn đang đặt một số câu hỏi tại đây Jarrod, bạn có thể cụ thể hơn không? Đó là, bạn chỉ muốn biết lý do tại sao phương pháp của bạn không thành công? Hoặc có thể bạn muốn một cách sử dụng các đối tượng dữ liệu trên các dự án khác nhau? Tôi giả sử bạn không cố gắng sử dụng LINQ to SQL như một lớp bản đồ cơ sở dữ liệu và bạn đang sử dụng nó như là một mô hình miền? Trong trường hợp nào, cả hai ứng dụng đều triển khai cùng một miền (quy trình nghiệp vụ, xác thực, v.v.)?

3

Tôi đã may mắn định nghĩa các lớp dữ liệu trong một assembly chung và tiêu thụ chúng trong nhiều assembly so với ánh xạ các lớp dữ liệu của nhiều assembly đến một hợp đồng chia sẻ. Sử dụng không gian tên ví dụ của bạn, đặt một DataContext tùy chỉnh và các lớp dữ liệu chia sẻ của bạn trong TestLinq2Sql.Shared:

namespace TestLinq2Sql.Shared 
{ 
    public class SharedContext : DataContext 
    { 
     public Table<User> Users; 
     public SharedContext (string connectionString) : base(connectionString) { } 
    } 

    [Table(Name = "Users")] 
    public class User 
    { 
     [Column(DbType = "Int NOT NULL IDENTITY", IsPrimaryKey=true, CanBeNull = false)] 
     public int Id { get; set; } 

     [Column(DbType = "nvarchar(40)", CanBeNull = false)] 
     public string Name { get; set; } 

     [Column(DbType = "nvarchar(100)", CanBeNull = false)] 
     public string Email { get; set; } 
    } 
} 

Sau đó, tiêu thụ DataContext từ bất kỳ lắp ráp khác:

using (TestLinq2Sql.Shared.SharedContext shared = 
    new TestLinq2Sql.Shared.SharedContext(
     ConfigurationManager.ConnectionStrings["myConnString"].ConnectionString)) 
{ 
    var user = shared.Users.FirstOrDefault(u => u.Name == "test"); 
} 
3

này trông giống như một lỗi - chúng tôi trường hợp đặc biệt Độc thân trên một khóa chính để làm một tra cứu địa phương nhưng có vẻ như con đường mã này không được lấy siêu dữ liệu đúng cách.

Các 1 = 1 Hack sẽ có nghĩa là nó đi qua một cơ sở dữ liệu bình thường khứ hồi nhưng thực sự là một lỗi nên được nộp ...

+1

Thực ra, có vẻ như một báo cáo lỗi đã tồn tại - với trạng thái "Đã đóng, sẽ không khắc phục". :( http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=394255 – daveidmx

5

Cố gắng bao gồm OfType trước mệnh đề WHERE

return _dbContext.GetTable<T>().OfType<T>().Where(expression).ToList();

+0

Wow, giải pháp duy nhất phù hợp với tôi, cảm ơn rất nhiều vì đã đăng bài này. – ViRuSTriNiTy

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