2009-02-23 32 views
18

Tôi có thể sẽ chịu trách nhiệm chuyển một ứng dụng vb6 sang C#. Ứng dụng này là một ứng dụng cửa sổ tương tác với một db truy cập. Việc truy cập dữ liệu được đóng gói trong các đối tượng kinh doanh cơ bản. Một lớp cho một bảng cơ bản. Các đối tượng kinh doanh vb6 hiện có đọc và ghi vào DB thông qua DAO. Tôi đã viết DAL và ORM một vài lần trước nhưng tất cả chúng chỉ nhắm mục tiêu SQL Server. Điều này sẽ cần phải nhắm mục tiêu truy cập và máy chủ sql. Trong các dự án trước, tôi sẽ đặt các chuỗi SQL trong các phần riêng của đối tượng nghiệp vụ và có thể di chuyển mã sql thừa như kết nối, tạo lệnh, vào một lớp cơ sở chung để giảm mã.Bạn đặt câu lệnh SQL vào các dự án C# ở đâu?

Lần này, tôi đang nghĩ đến việc viết chuỗi SQL vào tệp .settings hoặc một số tệp văn bản khóa/giá trị khác. Sau đó tôi sẽ viết một tiện ích sql để chỉnh sửa tệp này và cho phép tôi chạy và kiểm tra các truy vấn được tham số hóa. Các truy vấn này sẽ được tham chiếu theo tên trong đối tượng nghiệp vụ thay vì nhúng sql vào mã.

Tôi biết cách tiếp cận tiêu chuẩn là tạo DAL cho từng cơ sở dữ liệu được nhắm mục tiêu và có trạng thái cấu hình DAL để sử dụng. Tôi thực sự không muốn tạo hai lớp DAL cho mỗi cơ sở dữ liệu. Có vẻ như nó sẽ ít mã hơn nếu tôi chỉ tham chiếu truy vấn chính xác bằng tên khóa và có loại kết nối thích hợp.

Vì vậy, các bạn có đang làm những việc như thế này không? Làm thế nào hoặc có bạn tiếp cận vấn đề này? Điều gì phù hợp nhất với bạn?

Cảm ơn!

Trả lời

24

Vâng, có rất nhiều lựa chọn - vì vậy nó thực sự phụ thuộc vào những gì nhu cầu cấp bách nhất của bạn là :-)

Một cách tiếp cận có thể tạo câu lệnh SQL dưới dạng tệp văn bản bên trong giải pháp VS của bạn và đánh dấu chúng là "tài nguyên được nhúng" trong "hành động xây dựng". Bằng cách đó, SQL được bao gồm trong lắp ráp kết quả của bạn, và có thể được lấy ra từ nó trong thời gian chạy bằng cách sử dụng ResourceManifestStream của .NET framework:

private string LoadSQLStatement(string statementName) 
{ 
    string sqlStatement = string.Empty; 

    string namespacePart = "ConsoleApplication1"; 
    string resourceName = namespacePart + "." + statementName; 

    using(Stream stm = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) 
    { 
     if (stm != null) 
     { 
      sqlStatement = new StreamReader(stm).ReadToEnd(); 
     } 
    } 

    return sqlStatement; 
} 

Bạn cần phải thay "ConsoleApplication1" với không gian tên thực tế của bạn, trong đó các tệp câu lệnh sql cư trú. Bạn cần tham khảo chúng bằng tên của tên đầy đủ. Sau đó, bạn có thể tải câu lệnh SQL của mình với dòng này:

string mySQLStatement = LoadSQLStatement("MySQLStatement.sql"); 

Tuy nhiên, truy vấn này khá "tĩnh", ví dụ: bạn không thể cấu hình và thay đổi chúng trong thời gian chạy - chúng được nướng ngay vào các bit nhị phân đã biên dịch. Nhưng mặt khác, trong VS, bạn có một sự tách biệt rõ ràng giữa mã chương trình C# của bạn và các câu lệnh SQL.

Nếu bạn cần để có thể tinh chỉnh và thay đổi chúng khi chạy, tôi sẽ đặt chúng vào một bảng SQL có chứa e.g. một từ khóa và truy vấn SQL thực tế dưới dạng các trường. Sau đó, bạn có thể truy xuất chúng khi cần và thực thi chúng. Vì chúng nằm trong bảng cơ sở dữ liệu, bạn cũng có thể thay đổi, sửa chữa, sửa đổi chúng theo ý muốn - ngay cả khi chạy - mà không phải triển khai lại toàn bộ ứng dụng của bạn.

Marc

+1

Tôi đã sử dụng phương pháp này và tôi thích nó. Không giống như hầu hết mọi người, tôi không đồng ý với việc có thể thay đổi mã khi đang chạy, ngay cả các câu lệnh SQL đơn giản, vì vậy thực tế là nó được biên dịch với assembly là một điểm cộng với tôi. – Chris

+1

Vui mừng khi biết cách tiếp cận này đang được người khác sử dụng và chào đón! :-) Và tôi đồng ý - đôi khi công cụ nướng vào bit biên dịch của bạn là một lợi thế. –

+3

Thay vì không gian tênPart, sử dụng this.GetType() .Không gian tên cho phiên bản hiện tại, động, và typeof (Chương trình) .Không gian tên cho tĩnh. Tất nhiên khi bạn đặt nó vào lớp Program là tĩnh. Đừng quên, khi tệp SQL của bạn nằm trong thư mục SQL, hãy tham khảo nó bằng "SQL.StatementName.sql" – Harry

1

Tôi sẽ nói nơi tôi sẽ không đặt nó bao giờ, một cái gì đó tôi đã thấy thực hiện trong một số mã tôi thừa hưởng. Đó là trong Java, nhưng áp dụng cho bất kỳ ngôn ngữ

  • Một lớp cơ sở đó tuyên bố bảo vệ các biến thành viên tĩnh cho cho câu lệnh SQL, inited null, với một phương pháp get trả về câu lệnh SQL cá nhân

  • Một lớp tiểu cho mỗi máy chủ cơ sở dữ liệu được hỗ trợ, với một phương pháp init mà gán cho các biến thành viên lớp cơ sở

  • một số lớp DA rằng sử dụng phương thức lớp cơ sở để lấy câu lệnh SQL

  • Các ứng dụng khởi động lớp với trách nhiệm để tạo ra các đối tượng sub-class chính xác và gọi phương thức init của nó

Tôi cũng sẽ không đi vào giải thích lý do tại sao tôi sẽ không bao giờ làm điều này :-)

+2

Ngôn ngữ thuần túy OO gây ra những cơn ác mộng OO như thế này! buồn cười! – Steve

1

Một phương pháp mà chúng tôi sử dụng là có một lớp kết nối với DB và các phương thức gọi thủ tục và trong tham số phương thức, bạn sẽ cung cấp tên thủ tục. vì vậy tất cả các mã SQL là trong thủ tục. chúng tôi sẽ sử dụng quá tải cho các loại khác nhau trở lại

class ConnectToSQL() 
{ 
     //connectSql code (read from setting file i assume) 

     XMLDataDocument runProcedure(string procedureName); 
     int runProcedure(string procedureName); 

     //etc.... 
} 
+0

Bạn không thể có quá tải mà chỉ khác nhau theo kiểu trả về - nó sẽ cung cấp cho một lỗi biên dịch CS0111 – MattDavey

2

LINQ to DataSet vẻ như con đường để đi cho bạn.

Nếu bạn không sử dụng .NET 3.5 trước/LINQ thì bạn đang ở để điều trị. LINQ sẽ giúp bạn viết sql thô của bạn trong chuỗi ký tự chuỗi và cung cấp cho bạn một cách hợp lý hơn để tạo truy vấn.

Dù sao, kiểm tra liên kết này ra cho việc sử dụng LINQ trên cơ sở dữ liệu Access - http://msdn.microsoft.com/en-us/library/bb386977.aspx

9

Khi tôi thực sự cần nó, tôi đặt các truy vấn vào cá nhân * file sql, sau đó đưa vào Resources.resx. Có một phần 'Tệp' trong đó, cho phép bạn bao gồm các tệp Tài nguyên được nhúng.

Sau đó, tôi có thể sử dụng tài sản Resources.MyQuery được tạo ra, cả hai đều đảm bảo rằng tài nguyên tồn tại và lưu tôi khỏi viết phương thức tải tài nguyên tùy chỉnh.

+0

Tôi cũng thích giải pháp này. Các thuộc tính được tạo ra rất tiện dụng. – Steve

1

Nếu tôi phải tạo ứng dụng cho cả SQL và Access, tôi sẽ sử dụng một số giao diện IDAL, DALCommon với chức năng phổ biến và DALSql và DALAccess riêng biệt, được kế thừa từ DALCommon, với một số công cụ cụ thể, như trường hợp ngoại lệ, giao dịch xử lý, bảo mật, v.v.
Tôi đã sử dụng để giữ các tên thủ tục hoặc truy vấn được lưu trữ trong các tệp tài nguyên.

0

Đôi khi, giống như với các ứng dụng báo cáo tùy chỉnh, bạn thực sự cần phải nắm lấy sự không phù hợp trở kháng và đặc biệt quan trọng đối với SQL. Trong những trường hợp này, tôi khuyên bạn nên làm như sau: Đối với mỗi mô-đun có chứa chuỗi SQL, hãy tạo một lớp "SQL" tĩnh duy nhất để giữ tất cả chúng. Một số chuỗi SQL có thể sẽ yêu cầu các tham số, vì vậy hãy nhất quán và đặt từng chuỗi đằng sau phương thức tĩnh của chính nó.

Tôi chỉ làm điều này cho ứng dụng báo cáo tùy chỉnh không thường xuyên, nhưng nó luôn hoạt động tốt và cảm thấy sảng khoái và giải phóng. Và nó khá tốt đẹp để trở lại tháng sau đó để thực hiện một nâng cao, và tìm thấy tất cả các SQL đang chờ bạn trong một tập tin SQL.cs duy nhất. Chỉ bằng cách đọc một tệp, tất cả đều trở lại và thường là tệp duy nhất cần được thay đổi.

Tôi không thấy cần thiết trong những trường hợp này để ẩn SQL trong tài nguyên hoặc ở nơi khác. Khi SQL là quan trọng, thì điều đó quan trọng. Thật thú vị, ngày càng nhiều nhà phát triển đang tự do trộn SQL với C#, bao gồm cả tôi tin rằng trang web này, bởi vì về cơ bản, đó là những gì LINQ.

Cuối cùng, như mọi khi, hãy đảm bảo bạn không dễ bị tấn công SQL injection. Đặc biệt nếu đầu vào của người dùng có liên quan, hãy chắc chắn rằng bạn đang sử dụng một số loại tham số hóa và rằng bạn không sử dụng nối chuỗi.

0

Giải pháp nhúng được hiển thị ở trên có thể không hoạt động nếu truy vấn SQL có "ở đâu" giống như vậy, nhưng đối với cùng một truy vấn, lần chạy tiếp theo cần PropertyID = '113' làm PropertyID được đọc.

0

Glad you asked! Put your sql in a QueryFirst .sql template.

Nó tự động biên dịch vào ứng dụng của bạn như một nguồn tài nguyên nhúng, nhưng bạn không quan tâm. Bạn chỉ cần viết nó, trong một cửa sổ sql thực, kết nối với DB của bạn, với xác nhận cú pháp và intellisense cho các bảng và cột, sau đó sử dụng nó, thông qua các phương thức Execute() được tạo ra, với intellisense cho đầu vào và kết quả của bạn.

tuyên bố từ chối trách nhiệm: Tôi đã viết QueryFirst.

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