Lấy dữ liệu dùng Stored Procedure (LINQ to SQL phần 6)


Vài tuần trước tôi bắt đầu viết loạt bài về LINQ to SQL. LINQ to SQL là một bộ khung (framework) có sẵn cho O/RM (object relational mapping) trong .NET 3.5, nó cho phép bạn dễ dàng mô hình hóa các CSDL quan hệ dùng các lớp .NET. Bạn có thể dùng các biểu thức LINQ để truy vấn CSDL, cũng như có thể cập nhật/thêm/xóa dữ liệu từ đó.

Dưới đây là 5 phần đầu tiên của loạt bài này:

Trong các bài viết đó, tôi đã trình bài cách mà các bạn có thể dùng để lập trình lấy dữ liệu về từ CSDL.

Trong bài viết hôm nay, tôi sẽ cho thấy cách chúng ta có thể dùng các stored procedure (SPROCs) và các hàm do người dùng định nghĩa (UDFs) với mô hình dữ liệu LINQ to SQL. Bài viết này sẽ tập trung chủ yếu vào cách dùng SPROCs để truy vấn và lấy dữ liệu về từ CSDL. Trong bài viết kế tiếp, tôi sẽ hiển thị cách bạn có thể dùng các SPROCs để cập nhật, thêm, xóa dữ liệu từ CSDL.

Dùng SPROC hay không SPROC?  Đó là một vấn đề….

Câu hỏi liệu nên dùng các câu SQL động được sinh ra bởi trình ORM hay dùng Stored Procedure khi xây dựng lớp dữ liệu là một chủ đề không bao giờ kết thúc tranh cãi giữa các nhà phát triển, kiến trúc sư phần mềm và các DBA. Rất nhiều người thông minh hơn tôi nhiều đã viết về chủ đề này, vì vậy tôi sẽ không nói thêm về vấn đề này ở đây nữa.

LINQ to SQL đi cùng với .NET 3.5 rất mềm dẻo, và có thể được dùng để tạo các lớp mô hình dữ liệu, trong đó các đối tượng không phụ thuộc vào cấu trúc CSDL phía dưới, và có thể xử lý các phép kiểm tra logic cũng như xác thực tính hợp lệ của dữ liệu mà không phụ thuộc vào việc dữ liệu sẽ được lưu nạp dùng các câu SQL động hay thông qua các SPROCs.

Trong bài Truy vấn Cơ sở dữ liệu (phần 3), tôi đã thảo luận cách bạn có thể viết các biểu thức truy vấn LINQ cho một mô hình dữ liệu LINQ to SQL dùng đoạn mã như sau:

Khi bạn viết các biểu thức LINQ kiểu như vậy, LINQ to SQL sẽ thực thi các câu lệnh SQL động để bạn có thể lấy về các đối tượng khớp với câu truy vấn của bạn.

Như bạn đã được học trong bài viết này, bạn cũng có thể dùng các SPROCs trong CSDL trong lớp DataContext, nó cung cấp một cách khác để lấy về các đối tượng Products bằng cách gọi thủ tục tương ứng:

Khả năng này cho phép bạn dùng cả các câu SQL động và các SPROCs với một mô hình dữ liệu rõ ràng, mạnh mẽ cũng như cung cấp sự mềm dẻo khi làm việc với các dự án.

Các bước ánh xạ và gọi SPROC dùng LINQ to SQL

Trong phần 2, tôi đã nói về cách dùng LINQ to SQL designer để tạo ra một mô hình dữ liệu LINQ to SQL như dưới đây:

Ở cửa sổ trên có chứa 2 cửa sổ con, cửa sổ bên trái cho phép chúng ta định nghĩa mô hình dữ liệu sẽ ánh xạ vào CSDL, cửa sổ bên phải cho phép ánh xạ các thủ tục và hàm vào đối tượng DataContext, điều này cho phép chúng ta có thể thay thế các câu SQL động trong việc lấy dữ liệu về.

Cách ánh xạ một SPROC vào một DataContext của LINQ

Để ánh xạ một SPROC vào lớp DataContext, trước tiên hãy mở cửa sổ Server Explorer trong VS 2008 và mở danh sách các  SPROC trong CSDL:

Bạn có thể nháy đúp vào bất kỳ thủ tục SPROC nào ở trên để mở và chỉnh sửa chúng, ví dụ như “CustOrderHist” trong Northwind như dưới đây:

Để ánh xạ vào SPROC ở trên vào DataContext, bạn có thể kéo/thả nó từ cửa sổ Server Explorer lên trên cửa sổ LINQ to SQL designer. Việc này sẽ làm tự động sinh ra một thủ tục trong lớp DataContext của LINQ to SQL như dưới đây:

Mặc nhiên tên của phương thức được tạo trong lớp DataContext sẽ chính là tên của SPROC, và kiểu trả về của phương thức sẽ là một kiểu được tạo tự động với cách đặt tên theo dạng “[SprocName]Result”. Ví dụ: SPROC ở trên sẽ trả vef một dãy các đối tượng có kiểu “CustOrderHistResult”. Chúng ta có thể đổi tên của phương thức nếu muốn bằng cách chọn nó rồi dùng Property Grid để đặt lại tên khác.

Cách gọi SPROC mới được tạo

Khi đã hoàn thành các bước trên để ánh xạ một SPROC vào lớp DataContext của chúng ta, bạn có thể gọi nó một cách dễ dàng để lấy dữ liệu về. Tất cả những gì chúng ta cần làm là gọi phương thức mà chúng ta đã ánh xạ trong DataContext để lấy về một chuỗi các đối tượng về từ SPROC:

VB:

C#:

Thêm nữa, thay vì lặp qua tập kết quả như ở trên, tôi cũng có thể gắn nối nó vào cho một control để hiển thị ra màn hình, ví dụ như tôi có thể dùng <asp:gridview>:

Khi đó danh sách các sản phẩm được mua bở khách hàng sẽ được hiển thị như sau:

Ánh xạ kiểu trả về của phương thức SPROC vào một lớp trong mô hình dữ liệu

Trong thủ tục CustOrderHist ở trên, thủ tục trả về một danh sách dữ liệu bao gồm 2 cột: ProductName chứa tên và TotalNumber chứa số sản phẩm đã được đặt hàng trong quá khứ. LINQ to SQL designer sẽ tự động tạo ra một lớp có tên CustOrderHistResult để biểu diễn kết quả này.

Chúng ta cũng có thể chọn cách gán kiểu trả về của thủ tục cho một lớp có sắn trong mô hình dữ liệu, ví dụ một lớp thực thể Product hay Order.

Ví dụ, cho là chúng ta có một thủ tục tênGetProductsByCategory trong CSDL trả về thông tin sản phẩm giống như sau:

Cũng như trước đây, ta có thể tạo một phương thức GetProductsByCategory ở bên trong lớp DataContext mà nó sẽ gọi thủ tục này bằng cách kéo nó vào cửa sổ LINQ to SQL designer. Thay vì thả nó vào một vị trí bất kỳ, chúng ta sẽ thả nó lên trên lớp Product mà ta đã tạo ra sẵn trên sửa sổ này:

Việc kéo một SPROC và thả lên trên một lớp Product sẽ làm cho LINQ to SQL Designer tạo ra phương thức GetProductsByCategory trả về một danh sách các đối tượng có kiểu Product:

Một ưu điểm của việc sử dụng lớp Product như kiểu trả về là LINQ to SQL sẽ tự động quản lý các thay đổi được tạo ra trên đối tượng được trả về này, giống như được làm với các đối tượng được trả về thông qua các câu truy vấn LINQ. Khi gọi “SubmitChanges()” trên DataContext, những thay đổi này cũng sẽ được cập nhật trở lại CSDL.

Ví dụ, bạn có thể viết đoạn code giống như dưới đây (dùng một SPROC) và thay đổi giá của các sản phẩm bên trong một Category nào đó thành 90% giá trị cũ:

Khi gọi SubmitChanges, nó sẽ cập nhật lại giá của tất cả các sản phẩm. Để hiểu thêm về cách quản lý các thay đổi và cách phương thức SubmitChanges() làm việc, cũng như các thêm các phương thức xác thực logic dữ liệu, xin mời đọc lại bài 4 trong cùng loạt bài này.

Trong bài viết tiếp theo của loạt bài về LINQ to SQL, tôi sẽ hướng dẫn các bạn cách thay thế các câu lệnh SQL động cho việc INSERT/UPDATE/DELETE bằng các thủ tục SPROC. Và khi thay thế như vậy, bạn hoàn toàn không phải thay đổi gì trên các đoạn lệnh trên – việc thay đổi này hoàn toàn xảy ra trên mô hình dữ liệu và hoàn toàn trong suốt với các chương trình dùng nó.

Xử lý các tham số thủ tục dạng OUTPUT

LINQ to SQL ánh xạ các tham số dạng “OUTPUT” của các SPROC thành các tham biến (dùng từ khóa ref trong C# hoặc ByRef trong VB.NET), và với các tham trị, LINQ to SQL dùng các biến kiểu nullable (dùng ? trong C# hay <Nullable> trong VB.NET).

Ví dụ, thủ tục”GetCustomerDetails” sau sẽ nhận vào mộtCustomerID như tham số đầu vào, và trả về tên công ty như một tham số dạng OUTPUT và lịch sử giao dịch như kết quả truy vấn:

Nếu bạn kéo thủ tục trên để thả vào lớp Order trong LINQ to SQL designer, chúng ta có thể viết lệnh như sau để gọi nó:

VB:

C#:

Chú ý thủ tục trên vừa trả về một tập các đối tượng Order, đồng thời trả về CompanyName thông qua một tham số output.

Xử lý các thủ tục trả về nhiều kiểu kết quả khác nhau

Khi một thủ tục trả về nhiều kiểu kết quả khác nhau, kiểu trả về của phương thức trên lớp DataContext không thể được ép về một kiểu cụ thể nào đó. Ví dụ, thủ tục dưới đây có thể trả về một tập các sảm phẩm hay lệnh đặt hàng tùy thuộc vào tham số đầu vào:

LINQ to SQL hỗ trợ việc tạo các phương thức trợ giúp cho phép trả về Product hay Order bằng cách thêm một lớp partial NorthwindDataContext vào dự án và định nghĩa một phương thức trong lớp này (trong ví dụ này chúng ta gọi là VariablesShapeSample) để gọi thủ tục và trả về một đối tượng có kiểu IMultipleResult như trong ví dụ sau:

VB:

C#:

Một khi đã thêm phương thức này vào dự án, bạn có thể gọi và chuyển về kiểu thích hợp là Product hoặc Order:

VB:

C#:

Hỗ trợ các hàm do người dùng tự định nghĩa (UDF)

Thêm vào việc hỗ trợ các các thủ tục, LINQ to SQL còn hỗ trợ các hàm trả về các giá trị vô hướng hoặc các bảng kết quả. Một khi đã được thêm vào lớp DataContext như một phương thức, bạn có thể dùng các hàm UDF này trong câu trong các câu lệnh LINQ.

Ví dụ, hãy xem các hàm UDF đơn giản có tên MyUpperFunction sau đây:

Chúng ta có thể kéo và thả nó từ cửa sổ Server Explorer lên cửa sổ LINQ to SQL Designer để thêm nó vào lớp DataContext như một phương thức.

Chúng ta sau đó có thể dùng hàm UDF này ngay bên trong các biểu thức LINQ khi viết các câu truy vấn (giống như chúng ta đang dùng trong biểu thức Where như dưới đây):

VB:

C#:

Nếu bạn dùng LINQ to SQL Debug Visualizer mà tôi đã viết tại đây, bạn có thể thấy các LINQ to SQL chuyển đổi câu truy vấn ở trên thành câu lệnh SQL để thực thi hàm UDF khi chạy:

Tổng kết

LINQ to SQL supports the ability to call Stored Procedures and UDFs within the database and nicely integrate them into our data model.  In this blog post I demonstrated how you can use SPROCs to easily retrieve data and populate our data model classes.  In my next blog post in this series I’ll cover how you can also use SPROCs to override the update/insert/delete logic when you SubmitChanges() on your DataContext to persist back to the database.

LINQ to SQL hỗ trợ khả năng gọi các thủ tục và hàm trong CSDL và có khả năng tích hợp dễ dàng vào trong mô hình dữ liệu. Trong bài viết này tôi đã trình diễn cách dùng các thủ tục SPROC để dễ dàng truy xuất cũng như cập nhật các lớp mô hình dữ liệu. Trong bài kế tiếp tôi sẽ biểu diễn cách dùng SPROC để thực hiện việc cập nhật/thêm/xóa khi gọi SubmitChanges để cập nhật lại dữ liệu vào CSDL.

Hope this helps,

Scott

Các bạn đang xem bài viết trong loạt bài “LINQ to SQL”, loạt bài này được dịch từ blog ScottGu http://weblogs.asp.net/scottgu/

54 thoughts on “Lấy dữ liệu dùng Stored Procedure (LINQ to SQL phần 6)

  1. Rất cảm ơn bạn vì những bài viết hữu ích .
    Bạn có thể tổng hợp và chỉ rõ những ưu điểm và nhược điểm của LINQ
    ( LINQ to SQL ) giúp mình được ko ?
    thanks nhiều !! 🙂

  2. Chào anh !

    Tình cờ em tìm thấy trang web này của anh, nên ko biết rành rẽ mọi thứ lắm. Em cũng chưa đọc cặn kẽ bài viết của anh vì vấn đề em gặp lại ko được đề cập đến.

    Ví dụ như khi em cần gọi đến 1 Store Procedure, từ LinQ làm thế nào để em có thể lấy tên của Sproc và đối của nó như 1 tham số.

    Prototype:
    [CODE]
    class DataProvider
    {
    public Array CallSproc(String Name,params object[] param)
    {
    // here.
    }
    }
    [/CODE]

    Để giải quyết vấn đề này, tạm thời em dùng Switch Case ( If else ) để chọn Sproc cần gọi .

    Em cũng đã cố hỏi người khác ( ScottGu) những vẫn chưa nhận được câu trả lời. Tiếc quá. Hi vọng anh có thể reply cho em ( Dù được hay ko )

    btw, Thanks.

  3. Anh thực sự cũng chưa hiểu rõ yêu cầu của em, em có thể nói rõ hơn không?

  4. Yeah. Em thích trang đó thôi. Chứ gà lắm 🙂 hì hì.

    Câu hỏi của em thế này, bình thường để gọi 1 sproc thì anh dung sqlCommand.

    với tên và các đối số truyền vào.

    Bây giờ trong LinQ, em cũng muốn gọi 1 sproc theo tên là đối số của nó.

    Vd Trong csdl em có 2 sproc là :

    sproc: GetCustomerByCity(string city);
    sproc: GetCustomerByDate(DateTime from,DateTime end);

    Giờ em viết hàm gọi các Sproc này trong linQ :

    public Array CallSprocByName(String NameOfSproc,params object[] param)
    {
    /* Do em ko biết cách gọi do đó em gọi thế này :*/
    if(NameOfSproc == "GetCustomerByCity")
    {
    var result = dbDataContext.GetCustomerByCity((string) param[0])
    return result.ToArray();
    }
    else if( NameOfSproc == "GetCustomerByDate")
    {
    var result = dbDataContext.GetCustomerDate((DateTime)param[0],(DâteTime) param[1]);
    return result.ToArray();
    }
    return null;

    }

    Hi vọng là anh hiểu 🙂

  5. :), anh ngạc nhiên là khi LINQ đã làm đơn giản hóa vấn đề bằng cách tạo ra các hàm với các tham số đầy đủ, rõ ràng như vậy thì em lại làm phức tạp vấn đề. Nếu em làm vậy thà em sử dụng thẳng ADO.NET thì tốt hơn.

  6. Vâng. Vấn đề ko nằm chỗ của em, mà vấn đề nằm ở chỗ Thầy của em .

    Trong LinQ ( DataContext) có ExcuteQuery ( ExcuteCommand ) để em chạy đoạn query trực tiếp.

    Tiếp tục nữa là ở DAL. Ông thầy bảo là ko có nhiều hàm mà chỉ có 2 hàm. Hàm GetData(…) và Hàm SetData()

    Do đó phải giải quyết chuyện này. 😦
    Còn em thì vẫn thích cách có bao nhiều sproc thì có tương ứng bấy nhiều method gọi.

  7. Hic, thế thì chia buồn với em 😀
    Chính bản thân LINQ đã là một lớp DAL rất tốt rồi, anh không hiểu tại làm sao lại thêm 1 cái lớp DAL nào đó, mà lại chỉ có SetData và GetData. Xét về kiến trúc, khả năng đơn giản hóa, và cả tư duy thì đều … bad :p
    Anh không hiểu nếu em có 1 CSDL phức tạp, chẳng hạn 50 bảng, thì cái hàm Set và GetData đó nó sẽ phức tạp cỡ nào.

  8. Hi anh,

    Mấy hôm nay em relax bằng cách đọc Tru Tiên, mệt cả người. Ko vào thăm blog được 🙂

    Có mấy chỗ về LinQ cũng hay quá mà chưa thảo luận với anh được. Hi vọng 2 tuần nữa ( thi + đồ án xong xuôi ) thì có thể “đàm đạo” với anh tiếp.

    Còn về cái này thì do Thầy dạy em mang khuynh hướng cũ, tức là các lớp ở tầng Business giao tiếp với Persistance ( ko biết viết thế đúng ko ) thì giao tiếp qua 2 cách, 1 là đoạn sql, 2 là sproc với tên và tham số ( dùng sqlCommand) .

    Do đó thường chia ra rất ít hàm 😦

    Ví dụ GetData() thì thường là thế này :

    GetData(string sprocName,object[] sprocParam)
    {}

    rồi excute cái proc đấy 😀

  9. Hơ hơ, chỉ có GetData(string sprocName,object[] sprocParam) và SetData (chắc cũng khai báo tương tự) mà cũng gọi là một “tầng” =))
    Thế thì ta còn có cả tầng “ngày giờ hệ thống”, tầng “xử lý chuỗi” 😉

  10. Anh ơi em mới bắt đầu học Linq to sql. Em không biết làm thế nào để tạo ra một trigger giống như trong sql. Anh có thể nói về vấn đề này được không ạ

  11. LINQ to SQL chỉ cung cấp khả năng truy xuất CSDL, chứ bản thân nó không thể được dùng để tạo các đối tượng CSDL, do vây muốn tạo Trigger, em vẫn phải dùng SQL hay các thủ tục CLR.

  12. Nick anh có post trên blog này, chịu khó search nhé 😀
    Thực ra thì anh rất ít chat, trừ khi liên quan đến công việc, vậy nên cũng có nhiều người add vào nhưng hiếm khi chat.

  13. À, vậy thôi cũng được !

    Có mấy thứ trao đổi mà anh bận thì thôi vậy.

    Khi dùng LinQ anh trả về 1 Array thì ok.
    Nhưng nếu bên Design nó trả về 1 DataTable thì biết làm sao ?

  14. 1 DataTable thì cũng là 1 tập hợp dòng thôi mà, em cũng có thể dùng giống như 1 array.

  15. may quá, chào namdh. đọc cái này trên blog cá nhân của người nước ngoài mà dịch k rõ lắm, chỉ coi code roài hiểu. bi jo đọc lại thấy dễ hiểu hơn. Tiếng Việt muôn năm, hihi. Có điều mình có ý kiến thế này, có lẽ bạn dịch từ đó ra phải không, nếu vậy nên ghi lại link của trang đó để mọi người bít (tôn trọng tác giả chút ấy mà). Có gì sai bỏ quá cho nhá. Thanks bạn nhiều

  16. Thanks bạn,
    Có lẽ do bạn không theo dõi blog này lâu nên không biết, các tutorial trên blog này đều được dịch từ blog ScottGu, và mình nói điều này RẤT nhiều trên blog này :), thậm chí có bài mình còn giới thiệu ScottGu là ai, đang làm gì 🙂
    Hay như trong bài này, ngay cả tên Scott ở cuối mình cũng giữ nguyên, (mà không sửa thành ĐHN, he he).
    Tất nhiên vì quá trình khá lâu vì mình cũng bận, mỗi ngày chỉ dành khoảng 30 phút để dịch hoặc viết bài (một bài có thể mất mấy tuần mới xong) nên có một số bài không nói đến tác giả, chỉ khi review định kỳ lại thì mình mới sửa. Nhưng chắc chắn 100% là trong suốt 1 loạt bài, mình sẽ có nói đến điều này 🙂
    Dù sao cũng chân thành cảm ơn bạn

  17. uh, tại đang cần làm bài nên search ra cái tutorial này và chỉ xem phần part6 này thôi. Mình bít là dịch cái này để mọi người hiểu thì khá oải, còn nếu là bạn (hay mình coi) thì chỉ cần xem code là chính thì cũng hiểu được nhiều roài. Thanks bạn đã chia sẽ kiến thức cho mọi người

  18. Đọc cái discussion giữa kidkid với namdh mình thấy kidkid đúng là kid thật. LINQ là một kỹ thuật làm đơn giản cho chúng ta rất nhiều trong lập trình với CSDL. Nó bắc 1 “cây cầu” gọi là Object – Relation, tức là thường phía trên chúng ta coding quen với kiểu object nhưng CSDL thì lại nặng về quan hệ. LINQ đã mapping chúng lại với nhau để rút ngắn thời gian coding, dễ coding hơn, dễ thao tác với CSDL hơn. Đằng này kid thì lại muốn lấy cái mà nó muốn làm đơn giản đi làm cái phức tạp. Thật là nhiêu khê :d.

    Mình cũng hay đọc Scott’s Gruthie. Còn Đào Hải Nam thấy tên này cũng quen quen – giống tên học đại học với mình – đoán thôi

  19. hi, anh Nam
    Các kiểu trả về của các phương thức phụ thuộc vào cách mình đặt tên StoreProcedure hả anh?
    Em muốn trả về là “Tolist” thì phải đặt tên như thế nào vậy anh.
    Không hiểu cách đặt tên như thế nào mà em toàn trả về kiểu int, khi kéo Store í vào.
    Cảm ơn anh.

  20. Thầy ơi, theo em biết, thì LInQ thay thế rất tốt cho DAL, em có làm BL nhưng khi gọi 1 Store Proc thì kiểu trả về của nó là dạng ISingleResult với GetCategoriesByLevelWidthPos là tên của Proc. Và trên trang ascx, em phải casting từ Model (Em dùng mô hình MVC). Có cách nào khác để casting sang List không ạ. Em cast toàn báo lỗi là ko thể convert.

  21. Kiểu ISingleResult có implement từ IEnumerable mà em, sao lại phải cast làm gì cho mệt? 😀
    Lấy về rồi thì cứ foreach thôi.

  22. Em đã duyệt đc rồi, nhưng muốn cast sang List vì em muốn dùng List cho nhiều trường hợp khác.

  23. Anh Nam thân mến.
    Em đang tìm hiểu về silverlight.Bây jo em muốn làm một website đơn giản.cụ thể là trang đó bao gồm 1 trang default.apx, và một control menungang.sau đó gọi control này từ trang default.apx.trong đó menungang dữ liệu dc lấy từ cơ sở dữ liệu sql server 2005.
    Em dốt lắm.Anh Nam chỉ dùm nhé.

  24. em có cái store thế này: lấy 1 customer theo ID:

    ALTER PROCEDURE CustOrdersOrders @CustomerID nchar(5)
    AS
    SELECT*FROM Customer
    WHERE CustomerID = @CustomerID

    khi kéo vô ORM, em biết 2 cách để return value là Customer
    1.kéo store đó lên bảng Customer
    2.sau khi kéo vô ORM,đổi thuộc tính Return Value: (Auto-generated Type)–> Customer

    cho em hỏi còn cách nào khác để return value của cái store kia là Customer hay hok?

  25. Chào anh, e mới tìm hiểu về LinQ và gặp một số rắc rối trong việc viết code, cần sự hỗ trợ của anh.

    Dự án của e đã có sẵn, viết 3 tầng riêng biệt, trong đó e có 1 Core gọi là “Building” chuyên dùng để vẽ form của bảng dựa trên các thuộc tính được ép.

    ví dụ bảng Banner, trước đây e dùng thế này:

    public class Banner
    {
    private string _Name;

    [Build1(….)]
    [Build2(….)]
    public string Name
    get{return _Name};
    set{_Name=value};
    }

    trong đó Build1, Build2 là định dạng cho thuộc tính Name mà Core Build của em sẽ xử lý tương ứng để vẽ ra.

    Nhưng bây giờ ko được can thiệp trực tiếp vào Code của LinQ to SQL để viết như thế nữa (vì cứ sửa lại giao diện dbml là code lại refresh)

    Anh có cách nào giúp em vấn đề trên ko ạ?

    Nếu có thể đc thì a pm e qua nick “kienvang030805” nhe.

  26. anh chỉ nghĩ ra được 1 cách để giải quyết trường hợp này là tạo các “thuộc tính giả”, là wrapper của các thuộc tính có sẵn, sau đó đặt các thuộc tính mong muốn và vẽ dựa trên các thuộc tính này.
    Các thuộc tính giả này có kiểu tương tự như sau:

    public partial class Banner
    {

    [Build1(….)]
    [Build2(….)]
    public string NameWrapper
    get{return Name};
    set{Name=value};
    }

  27. Cho mình hỏi cái này, không biết ai đã từng thử chưa. Đó là mình có 1 cái stored mà select 1 cái table tạm đuợc tạo ra trong stored đó, khi kéo vào thì nó trả về int thay vì trả về IsingleResult, làm cách nào để nó trả về IsingleResult nhỉ.
    Thanks,

  28. anh ơi cho em hỏi.
    Giờ em có store như vầy:

    ALTER PROCEDURE [dbo].[Them_Tinh1]
    @Ma_QG int,
    @Ten_Tinh nvarchar(50),
    @bientv char(1) output
    AS
    begin
    if exists(Select * from Tinh Where [Ma_QG]=@Ma_QG and [Ten_Tinh]=@Ten_Tinh )
    begin
    print’Tinh nay da ton tai roi’
    Select bientv=’a’
    return

    end
    elsE
    begin tran
    INSERT INTO TINH
    (
    Ma_QG,
    Ten_Tinh
    )
    VALUES
    (
    @Ma_QG,
    @Ten_Tinh

    )
    If (@@error 0)
    begin
    Print’Da them that bai’
    Select bientv=’b’
    Rollback tran
    return
    end
    Else
    begin
    Print’Da them thanh cong’
    Select bientv=’c’
    Commit tran
    return
    end

    End
    và gọi lại như sau:
    char? kiemTra;
    db.Them_Tinh1(int.Parse(txtMa.Text), txtTen.Text,ref kiemTra);
    Khi em thực thi nó báo lỗi là:
    Use of unassigned local variable ‘kiemTra’

  29. em phải gán giá trị cho kiemTra trước khi gọi

    char? kiemTra = 0;

  30. anh ơi cho em hoi em viết cái sp:
    ALTER PROCEDURE dbo.myspTest
    @temp int output
    as
    begin
    declare @id int
    set @id=1
    while exists(select iduser from taikhoan where iduser=@id)
    set @id=@id+1
    begin
    select @temp=@id
    return
    end
    end
    và trong code em viết hàm lấy kết quả của sp
    public static int ketqua()
    {
    int id = 0;
    LinQDataContext linq = new LinQDataContext();
    linq.myspTest(ref id);[lỗi]
    return id;
    }
    sao nó lại báo lỗi ngay dòng[lỗi]
    đây là lỗi nó báo Error 6 The best overloaded method match for ‘LinQ.LinQDataContext.myspTest(ref int?)’ has some invalid arguments

  31. Chào Nam!

    Hiện tại mình đang nghiên cứu về Linq, và đăng mắc về khoản Return Value khi sử dụng Linq – store Procedure.

    Mình xin trình bày như sau.

    Mình có store procedure như sau

    Create PROC procLogin @user varchar(50),@pass varchar(50)

    AS

    BEGIN

    Select * from hethong,nhanvien

    where hethong.manhanvien = nhanvien.manhanvien

    And hethong.password=@pass and hethong.username=@user

    END

    Mình làm window form theo mô hình 3 – tier

    – Trong project DTO có class LoginDTO có nội dung như sau

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    namespace DTO

    {

    public class LoginDTO

    {

    public string ChucVu { get; set; }

    public string Username { get; set; }

    public string TenNV { get; set; }

    public string MaNV { get; set; }

    }

    }

    – Quan trọng hơn, trong project DAO có class LoginDAO có đoạn code như sau, và mình mắc ở đoạn này

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Data.Linq.Mapping;
    using System.Data.Linq;
    using System.Text;
    using DTO;

    namespace DAO
    {
    public class LoginDAO
    {
    public const int limitList = 5;
    public IList Login(string user, string pass)
    {
    HotelDataContext htDataContext = new HotelDataContext();
    // Sử dụng Linq – store procedure – đoạn này mình đang mắc
    ISingleResult Login = htDataContext.procLogin(user, pass);
    LoginDTO lgDTO = new LoginDTO();
    foreach (procLoginResult rs in Login)
    {

    lgDTO.ChucVu = rs.chucvu;
    lgDTO.Username = rs.username;
    lgDTO.MaNV = rs.manhanvien;
    lgDTO.TenNV = rs.tennhanvien;
    }
    return (ISingleResult)(Login.ReturnValue); // Mình không biết return, hay là convert về kiểu Ilist như thế nào

    // Mình muốn hỏi là làm thế nào để trả về một danh sách ToList, hay làm thế nào để đoạn code bên trên có thể sử dụng tương đương với đoạn code bên dưới đây.
    // Không sử dụng Linq – store procedure – đoạn dưới thì ok rồi
    // var querry = (
    // from ht in htDataContext.hethongs
    // from nv in htDataContext.nhanviens
    // where ht.manhanvien == nv.manhanvien &&
    // ht.password == pass && ht.username == user
    // select new LoginDTO
    // {
    // Username = ht.username,
    // ChucVu = nv.chucvu,
    // MaNV = nv.manhanvien,
    // TenNV = nv.tennhanvien
    // }
    // ).Distinct();
    // return querry.ToList();
    // Mình muốn đoạn code bên trên trả về như thế này return querry.ToList();
    }
    }
    }

    – Trong lớp BUS có đoạn code như sau

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using DAO;

    using DTO;

    namespace BUS

    {

    public class LoginBUS

    {

    LoginDAO lgDAO = new LoginDAO();

    public IList Login(string user, string pass)

    {

    try

    {

    return lgDAO.Login(user, pass);

    }

    catch

    {

    throw new Exception(“Error!”);

    }

    }

    }

    }

    – Mong hồi âm, cám ơn đã đọc!

  32. Mình có một đoạn code thế này bạn có thể áp dụng vào đoạn code của bạn nhé

    public List ListObject()
    {
    Context = new ;
    var Query = Context.
    List Lists = new List();
    foreach (var in Query)
    {
    Đối tượng = new
    . = .Cột
    List.Add();
    }
    return Lists
    }

  33. Mình có một đoạn code thế này bạn có thể áp dụng vào đoạn code của bạn nhé

    public ListĐối tượng ListObject()
    {
    Tên DataContentText Context = new Tên DataContentText
    var Query = Context.Phương thức truy vấn
    List Đối tượng Lists = new List Đối tượng;
    foreach (var Biến in Query)
    {
    Đối tượng Đối tượng bạn mong muốn = new Đối tượng
    Đối tượng bạn mong muốn.Thuộc tính = Biến.Cột
    List.Add(Đối tượng bạn muốn);
    }
    return Lists
    }

  34. làm ơn giúp em với. em có proc
    ALTER PROCEDURE [dbo].[spm_Top_Market_Movers]
    — Add the parameters for the stored procedure here
    @ID int
    AS
    BEGIN
    — SET NOCOUNT ON added to prevent extra result sets from
    — interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @MaxDate datetime

    SELECT @MaxDate = MAX(Ngay) FROM tblGiaLichSuMaCK
    DECLARE @PreDate datetime
    SELECT @PreDate = Ngay FROM
    (
    SELECT Ngay, ROW_NUMBER() OVER (ORDER BY Ngay DESC) Row
    FROM
    (
    SELECT DISTINCT TOP 2 Ngay FROM tblGiaLichSuMaCK ORDER BY Ngay DESC
    ) tbl
    ) tbl WHERE Row = 2

    CREATE TABLE #temp
    (StockSymbol nvarchar(50), GiaDieuChinh decimal(18,4), BienDong decimal(18,4), PhanTran decimal(18,4), ThayDoiVonHoa decimal(18,4))

    DECLARE @TongThayDoiVonHoa decimal(18,4)
    SET @TongThayDoiVonHoa = 0

    INSERT INTO #temp
    SELECT t.StockSymbol,t.GiaDieuChinh, t.GiaDieuChinh – t1.GiaDieuChinh BienDong,
    (t.GiaDieuChinh/t1.GiaDieuChinh – 1) * 100 PhanTran,
    (t.GiaDieuChinh – t1.GiaDieuChinh) * vv.SLCPNiemYet ThayDoiVonHoa
    FROM
    (
    SELECT ls.MaCK StockSymbol, ls.Ngay TradeDate, ls.GiaDieuChinh
    FROM tblGiaLichSuMaCK ls
    WHERE SanGD = @ID AND DATEDIFF(DAY, ls.Ngay, @MaxDate) = 0
    ) t
    INNER JOIN
    (
    SELECT ls.MaCK StockSymbol, CASE ls.GiaDieuChinh WHEN 0 THEN NULL ELSE ls.GiaDieuChinh END GiaDieuChinh
    FROM tblGiaLichSuMaCK ls
    WHERE SanGD = @ID AND DATEDIFF(DAY, ls.Ngay, @PreDate) = 0
    ) t1 ON t.StockSymbol = t1.StockSymbol
    INNER JOIN solieu_view_fe_tempHistoryVolume_GetCurrentVolume vv ON vv.Symbol= t.StockSymbol

    SELECT @TongThayDoiVonHoa = @TongThayDoiVonHoa + ThayDoiVonHoa FROM #temp

    IF(@TongThayDoiVonHoa = 0) SET @TongThayDoiVonHoa = NULL

    SELECT TOP 10 t.StockSymbol, t.GiaDieuChinh AveragePrice, t.BienDong change, t.PhanTran perc,
    t.GiaDieuChinh BasicPrice, 0 SLCPNY, ” link
    FROM
    (
    SELECT t.StockSymbol, t.GiaDieuChinh, t.BienDong, t.PhanTran, t.ThayDoiVonHoa / @TongThayDoiVonHoa E
    FROM #temp t
    ) t
    ORDER BY t.E DESC

    END

    nhưng khi kéo vào linq nó tự chuyển sang kiểu void ko có kết quả trả về. Hix. làm ơn giúp em

  35. làm ơn giúp em với. em có proc
    ALTER PROCEDURE [dbo].[spm_Top_Market_Movers]
    — Add the parameters for the stored procedure here
    @ID int
    AS
    BEGIN
    — SET NOCOUNT ON added to prevent extra result sets from
    — interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @MaxDate datetime

    SELECT @MaxDate = MAX(Ngay) FROM tblGiaLichSuMaCK
    DECLARE @PreDate datetime
    SELECT @PreDate = Ngay FROM
    (
    SELECT Ngay, ROW_NUMBER() OVER (ORDER BY Ngay DESC) Row
    FROM
    (
    SELECT DISTINCT TOP 2 Ngay FROM tblGiaLichSuMaCK ORDER BY Ngay DESC
    ) tbl
    ) tbl WHERE Row = 2

    CREATE TABLE #temp
    (StockSymbol nvarchar(50), GiaDieuChinh decimal(18,4), BienDong decimal(18,4), PhanTran decimal(18,4), ThayDoiVonHoa decimal(18,4))

    DECLARE @TongThayDoiVonHoa decimal(18,4)
    SET @TongThayDoiVonHoa = 0

    INSERT INTO #temp
    SELECT t.StockSymbol,t.GiaDieuChinh, t.GiaDieuChinh – t1.GiaDieuChinh BienDong,
    (t.GiaDieuChinh/t1.GiaDieuChinh – 1) * 100 PhanTran,
    (t.GiaDieuChinh – t1.GiaDieuChinh) * vv.SLCPNiemYet ThayDoiVonHoa
    FROM
    (
    SELECT ls.MaCK StockSymbol, ls.Ngay TradeDate, ls.GiaDieuChinh
    FROM tblGiaLichSuMaCK ls
    WHERE SanGD = @ID AND DATEDIFF(DAY, ls.Ngay, @MaxDate) = 0
    ) t
    INNER JOIN
    (
    SELECT ls.MaCK StockSymbol, CASE ls.GiaDieuChinh WHEN 0 THEN NULL ELSE ls.GiaDieuChinh END GiaDieuChinh
    FROM tblGiaLichSuMaCK ls
    WHERE SanGD = @ID AND DATEDIFF(DAY, ls.Ngay, @PreDate) = 0
    ) t1 ON t.StockSymbol = t1.StockSymbol
    INNER JOIN solieu_view_fe_tempHistoryVolume_GetCurrentVolume vv ON vv.Symbol= t.StockSymbol

    SELECT @TongThayDoiVonHoa = @TongThayDoiVonHoa + ThayDoiVonHoa FROM #temp

    IF(@TongThayDoiVonHoa = 0) SET @TongThayDoiVonHoa = NULL

    SELECT TOP 10 t.StockSymbol, t.GiaDieuChinh AveragePrice, t.BienDong change, t.PhanTran perc,
    t.GiaDieuChinh BasicPrice, 0 SLCPNY, ” link
    FROM
    (
    SELECT t.StockSymbol, t.GiaDieuChinh, t.BienDong, t.PhanTran, t.ThayDoiVonHoa / @TongThayDoiVonHoa E
    FROM #temp t
    ) t
    ORDER BY t.E DESC

    END

    nhưng khi kéo vào linq nó tự chuyển sang kiểu void ko có kết quả trả về. Hix. làm ơn giúp em

  36. Mong anh giúp em câu truy vấn này nhé

    —-Em có proc sau: nhiệm vụ là trả về Mã Nhân Viên cuối cùng trong database -> làm mã tự sinh khi Insert, với biến ra là @manv
    —- Biết rằng Chucvu truyền vào có thể là Nhân viên/Quản lý

    ALTER proc [dbo].[proGetMnv](@chucvu nvarchar(50),@manv nvarchar(50) OUTPUT)
    as
    Begin
    select top(1) manhanvien
    from dbo.nhanvien
    where nhanvien.chucvu=@chucvu
    order by manhanvien desc
    return @manv
    END


    —- Nhưng mà em vẫn không hiểu làm sao gọi stored procedure trong Linq có trả về giá trị như trên.
    —- Anh có thể viết hàm để gọi lại cái stored proc trên nhé, nếu có thể thì viết hàm trả về giá trị, vì em làm theo mô hình 3-tiers mà.
    —- Mong anh hồi âm, thanks

  37. Em có thể kéo thả proc em tạo vào cửa sổ design để tạo phương thức tương ứng trong data context, sau đó gọi như như sau:

    var context = new MyDataContext();
    context.proGetMnv(chucvu, ref nhanvien);

  38. Em đã thử nhưng chưa được anh ạ. Anh có thể viết rõ hơn được không?
    Giả sử dữ liệu là 1 string và đổ vào 1 textbox.
    – Cám ơn anh đã hồi âm!

  39. Kính gửi: Thầy Hải Nam,

    Hương đang viết 1 thủ tục và đưa lên frm viết bằng ngôn ngữ VB.NET-LINQ nhưng do chưa rành cách gọi thủ tục(mới đọc tham khảo hướng dẫn bài của Thầy Hải Nam viết thôi) nên chương trình chạy không được.
    Rất mong Thầy chỉ giúp.
    Thủ tục:

    ALTER proc [dbo].[usp_TinhTongThieu]
    (@SoTBNP nchar(15))
    as
    Begin
    Declare @TongTienDaTra real,@SoTienPhaiTra real
    set @TongTienDaTra=(select sum(SoTienDaTra) from DanhSachThuTien
    where SoTBNP=@SoTBNP)
    set @SoTienPhaiTra=(select TOP 1 SoTienPhaiTra from DanhSachThuTien where SoTBNP=@SoTBNP order by SoTienPhaiTra desc)
    if @TongTienDaTra<@SoTienPhaiTra
    begin
    declare @TongTienThieu real
    set @TongTienThieu=@SoTienPhaiTra-@TongTienDaTra
    print @TongTienThieu

    end
    else
    print 'Khong'

    end

    Đưa lên frm:

    Sub HienThiTinhTongTienLenTextBox_SoTienTraThieu()
    Dim danhSachThuTienBus As New DanhSachThuTienBUS()
    Dim ThuPhiCSDL As New ThuPhiCSDLDataContext()

    Dim intNumber As Object = ThuPhiCSDL.usp_TinhTongThieu(cboSoTBNP.SelectedText.ToString())
    'Dim tongTienThieu As String = TryCast(intNumber, String)
    Dim SoTienTraThieu As String = TryCast(intNumber, String)
    txtSoTienTraThieu.Text = SoTienTraThieu

    'For Each DanhSachThuTien In SoTienTraThieu
    'txtSoTienTraThieu.Text = DanhSachThuTien.SoTienTraThieu
    'txtSoTienTraThieu.Text = danhSachThuTienBus.SoTienTraThieu
    'Next
    End Sub

    Rất mong sự hướng dẫn của Thầy!

  40. Lệnh print trong SP không có tác dụng gì khi em gọi thủ tục trong .NET
    Phải sửa lại để TongTienThieu trở thành 1 tham số dạng output, sau đó tính toán, nếu không nợ thì TongTienThieu = 0, ngược lại là số tiền nợ.

    Gọi thủ tục này từ .NET app bằng LINQ to SQL, truyền thêm tham số TongTienThieu (khi kéo thả lại SP, nó sẽ tự sinh thêm tham số này). Sau khi gọi xong, kiểm tra giá trị của TongTienThieu để thực hiện thao tác cần thiết tiếp theo.

  41. Kính gửi: Thầy,
    Đúng là buồn ngủ gặp chiếu manh, Hương đang làm đồ án có liên quan đến thực tế nên gặp khá nhiều điều mình còn chưa biết xử lý, cả tuần nay đọc bài của Thầy viết về cách gọi thủ tục và tìm cách upload bài nhưng ko được cứ yêu cầu xác nhận lại hoài, hôm nay H lại tiếp tục upload bài lên với hy vọng được Thầy hướng dẫn, tối về H sẽ sửa lại theo hướng dẫn của Thầy để chạy thử.
    Hương cảm ơn Thầy nhiều.

  42. Kính gửi: Hương,

    Đề nghị em không “Kính gửi: Thầy” nữa, nghe nó hoành tá tràng quá 😀

  43. KidKid
    “À, vậy thôi cũng được !

    Có mấy thứ trao đổi mà anh bận thì thôi vậy.

    Khi dùng LinQ anh trả về 1 Array thì ok.
    Nhưng nếu bên Design nó trả về 1 DataTable thì biết làm sao ?”
    Tuy ít khi tham khảo nhưng nay thấy kidkid hỏi mình củng xin chỉ một cách chuyển từ Array to DataTable

    //SPRoc lấy mã kích hoạt của mình LINQ tu sinh———————————————————-

    [Function(Name=”dbo.spSelect_MaKichHoat_ID”)]

    public ISingleResult spSelect_MaKichHoat_ID([Parameter(DbType=”NVarChar(250)”)] string chuoi, [Parameter(DbType=”NVarChar(10)”)] string masp)
    {
    IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), chuoi, masp);
    return ((ISingleResult)(result.ReturnValue));
    }

    //Lớp truy xuất SPRoc minh viết trả về một List dang XML—————————————————–
    public partial class MS_Process
    {
    //Lấy mã kích hoạt theo ID và MSP
    public string MaKichHoat_DanhSach_ID(string makichhoat, string masp)
    {
    List obj = new List(db.spSelect_MaKichHoat_ID(makichhoat, masp));
    if (obj.Count > 0) log.WriteLine(LogType.select, “MaKicHoat”);
    return func.SerializeObjectToString((object)obj);
    }

    //Cập nhật Mã kích hoạt sau khi đã kích hoạt sản phẩm
    public bool MaKichHoat_Register(string dataStream)
    {
    try
    {
    MaKichHoat obj = func.DeserializeStringToObject(dataStream);
    if (db.spMaKichHoat_Register(obj.IDKichHoat, obj.NgayKichHoat, obj.NgayHetHan, obj.ThongTinHDD) != 1)
    {
    db.SubmitChanges();
    log.WriteLine(LogType.edit, “makichhoat”);
    return true;
    }
    else { return false; }
    }
    catch { return false; }
    }
    }
    #endregion

    //Chuyển XML về DataTable
    public DataTable MaKichHoat_SelectAll_ID(string makichhoat, string masp)
    {
    DataTable dt = new DataTable();

    StringReader theReader = new StringReader(ms_st.MaKichHoat_DanhSach_ID(makichhoat, masp));
    DataSet theDataSet = new DataSet();
    theDataSet.ReadXml(theReader);
    return theDataSet.Tables[0];

    }

  44. anh nam ơi cho em hỏi là làm sao để mình dùng hàm Take() trong C# khi mà sử dụng LINQ, em có dùng nhưng mà không hiển thị lên kết quả
    đây là code của em

    var q = NS.SACHBANCHAY(Tungay, Denngay).Take(5);
    gridControl1.DataSource = q;

  45. a cho e hỏi khi mình kéo 1 store vào trong một class trong file . dbml thì nó hiện ra lỗi như thế này:
    “one or more selected database objects return a schema that does not match the schema of the target data class. nothing has been added to the designer”.
    a chỉ giúp e với.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s