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:
- Sử dụng LINQ to SQL (phần 1)
- Định nghĩa các lớp mô hình dữ liệu (phần 2)
- Truy vấn Cơ sở dữ liệu (phần 3)
- Cập nhật cơ sở dữ liệu (LINQ to SQL phần 4)
- Sử dụng asp:LinqDataSource (phần 5)
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/
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 !! 🙂
Bạn có thể tham khảo tại đây: https://namdh.wordpress.com/2008/12/08/linq-faq/
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.
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?
À mà em cũng ở bên gamedev à ?
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 🙂
:), 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.
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.
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.
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 😀
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” 😉
he he.
Lay’ Lam` Xau’ Ho Vay.
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 ạ
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.
anh Nam cho em nick dc ko?
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.
À, 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 ?
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.
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
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
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
Đọ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
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.
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.
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.
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.
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é.
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?
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.
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};
}
Bài viết khá hay.Thank
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,
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’
em phải gán giá trị cho kiemTra trước khi gọi
char? kiemTra = 0;
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
Em khai báo lại int id = 0; thành int? id;
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!
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
}
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
}
@Hoàng Văn Quế: Cảm ơn bạn đã trả lời giúp
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
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
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
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);
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!
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!
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.
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.
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á 😀
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];
}
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;
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.