Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos 1 Part 1. An Experience Using LINQ to SQL Exploring the LINQ Entity-Model What is LINQ ? 1[1] Language Integrated Query (or LINQ, pronounced “link”), is a set of Microsoft .NET technologies that provide built-in language querying functionality similar to SQL, not only for database access, but for accessing data from any source. The current LINQ family of technologies and concepts allows an extensible set of operators that work over objects, SQL data and XML data sources. It is expected that LINQ will expand in the future to a larger number of data domains. A gentle Introduction to LINQ [2] Let us consider the following C# code fragment using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConLinq1 { class Program { static void Main() { string[] myNames = { "Burke", "Connor", "Frank", "Bingo", "Bango", "Bongo", "Everett", "Albert", "George", "Becky", "Harris", "David" }; // make a list of names made of 5 characters var expr = from s in myNames where ((s.Length == 5) && (s.StartsWith("B"))) orderby s select s.ToUpper(); // show results foreach (string item in expr) Console.WriteLine(item); // show actual type of anonymous variable Console.WriteLine("expr type:\n" + expr.GetType()); Console.WriteLine("\nDone..."); Console.ReadLine(); } }//class } 1 [1] Taken from http://msdn.microsoft.com/en-us/library/bb386976.aspx [2] The LINQ Project .NET Language Integrated Query. Don Box and Anders Hejlsberg. Microsoft Corporation. May 2006. Available at http://download.microsoft.com/download/5/8/6/5868081c-68aa-40de-9a45-a3803d8134b8/LINQ_Project_Overview.doc
41
Embed
Part 1. An Experience Using LINQ to SQL Exploring the LINQ ...cis.csuohio.edu/~sschung/CIS408/LinqTutorial.pdf · LINQ to SQL is an (O/RM) Object Relational Mapping component of the
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
1
Part 1. An Experience Using LINQ to SQL
Exploring the LINQ Entity-Model
What is LINQ ? 1[1]
Language Integrated Query (or LINQ, pronounced “link”), is a set of Microsoft .NET technologies that provide built-in
language querying functionality similar to SQL, not only for database access, but for accessing data from any source.
The current LINQ family of technologies and concepts allows an extensible set of operators that work over objects,
SQL data and XML data sources. It is expected that LINQ will expand in the future to a larger number of data
domains.
A gentle Introduction to LINQ [2]
Let us consider the following C# code fragment
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConLinq1 { class Program { static void Main() { string[] myNames = { "Burke", "Connor", "Frank", "Bingo", "Bango", "Bongo", "Everett", "Albert", "George", "Becky", "Harris", "David" }; // make a list of names made of 5 characters var expr = from s in myNames where ((s.Length == 5) && (s.StartsWith("B"))) orderby s select s.ToUpper(); // show results foreach (string item in expr) Console.WriteLine(item); // show actual type of anonymous variable Console.WriteLine("expr type:\n" + expr.GetType()); Console.WriteLine("\nDone..."); Console.ReadLine(); } }//class }
1 [1] Taken from http://msdn.microsoft.com/en-us/library/bb386976.aspx [2] The LINQ Project .NET Language Integrated Query. Don Box and Anders Hejlsberg. Microsoft Corporation. May 2006. Available at http://download.microsoft.com/download/5/8/6/5868081c-68aa-40de-9a45-a3803d8134b8/LINQ_Project_Overview.doc
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
5
DataContext class created will have properties that represent each Table we modeled within the database, as well as
methods for each Stored Procedure we added.
It tracks changes that you made to all retrieved entities and maintains an "identity cache" that guarantees that entities
retrieved more than one time are represented by using the same object instance. In general, a DataContext instance is
designed to last for one "unit of work" however your application defines that term.
The DataContext class contains the connection string information and the methods for connecting to a database and
manipulating the data in the database. By default, the DataContext class contains several methods that you can
call, such as the SubmitChanges method that sends updated data from LINQ to SQL classes to the database. You can
also create additional DataContext methods that map to stored procedures and functions. In other words, calling
these custom methods will run the stored procedure or function in the database that the DataContext method is
mapped to. You can add new methods to the DataContext class just as you would add methods to extend any class.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
6
Lab Experience
We assume you have installed a copy of the COMPANY database in your SQL-Server (for details about the datasets
consult Elmasri-Navathe textbook).
1. Create a new C# project. Call it Linq2Sql01
2. Open the Server Explorer and create a new Data Connection to the MS-SQL COMPANY database (see MS-SQL
Database Diagram in Appendix A).
3. You must add to the C# project a Linq class. Follow the steps:
(Main Menu) Project | Add New Item… | Linq to Sql class. Name it: CompanyLinq.dbml. Click OK
Figure 1. Adding a Linq to Sql class
Figure2. The Object/Relational Designer Surface
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
7
4. Click on the Server Explorer. Open the Tables folder. Drag the EMPLOYEE, WORKS_ON, and PROJECT tables to the
Object-Relational Designer panel (see figure above). This diagram depicts the collection of entities and their defined
relationships (other components could be added later). Those elements are accessible from our application.
Figure 3. A Class-Diagram showing three entities (Employee, Works_On, Project) and their relationships.
5. Enter the following code:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Linq2Sql01 { class Program { static void Main(string[ ] args) { //demo1. Retrieve male employees CompanyLinqDataContext myContext = new CompanyLinqDataContext(); var query1 = from e in myContext.EMPLOYEEs where e.sex.Equals("M") select e; foreach (var e in query1) { Console.WriteLine("Name: {0} {1} \tDno: {2}", e.fname, e.lname, e.dno); } Console.WriteLine("\nDone..."); Console.ReadLine(); } } }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
8
Output
Observations
a) The new LINQ class was called CompanyLinq. Therefore its associated DataContext class is named:
CompanyLinqDataContext
b) The clause “var query1” defines query1 as a variable of “anonymous type”. The shape of query1 is dictated by
the result of the LINQ expression. In our example the type of query1 is similar to Employee type.
c) The LINQ expression consists of three parts: from … where … select …
d) In our example the “from” portion is: from e in myContext.EMPLOYEEs. The collection EMPLOYEEs is
provided by .NET as a way of traversing the EMPLOYEE table (its naming is done by .NET)
e) The filtering of data is done through the phrase: where e.sex.Equals(“M”). The condition is written in the
form expected by the host language (in this case C#). For instance, the previous expression could also be
written as where e.sex == „M‟. Notice that Intellisense provides a list of e attributes as soon as you type “e.”
f) The select clause defines the output. In this example the entire e data type is retrieved. You may use the
expression new (e. fname, e.Lname, e.dno) to create a new entity type holding the three attributes: first
name, last name, and dept. number.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
9
Organizing the Rest of the Tutorial.
Replace the main method entered before with the following (larger) sample. You can try each of the fragments by
uncommenting/commenting the corresponding demo (there are nine altogether).
using System; using System.Collections.Generic; using System.Linq; using System.Text; // trying LINQ on the company database namespace Linq2SqlCompany01 { class Program { static void Main(string[] args) { // STEP 1 // Open the Server Explorer. Add a New Connection to the // MS-SQL Database called: Company // --------------------------------------------------------------- // STEP 2. // You must add to the project a Linq class, do this // Main Menu Project | Add New Item | Linq to Sql class // name it: CompanyLinq.dbml. Click OK // ---------------------------------------------------------------- // STEP3 // Define a Linq Data-Contex object CompanyLinqDataContext myContext = new CompanyLinqDataContext(); try { // QUERY1: Listing all MALE employees //ShowMaleEmployees(myContext); // QUERY2: List all employees and projects in which they work //ShowEmployeesProjects1(myContext); //QUERY3. Similar to Query2 but using a 'JOIN' expression //ShowEmployeesProjects2(myContext); //DEMO4: Insert a new assignment for employee 123456789 //InsertSingleAssignment(myContext); //DEMO5: Insert multiple assignment for employee 123456789 //InsertMultipleAssignments(myContext); //DEMO6: Delete one assignment for 123456789 //DeleteSingleAssignment(myContext); //DEMO7: Delete multiple assignment for 123456789 (pno >= 10) //DeleteMultipleAssignments(myContext); //DEMO8: Using STORED PROC. Simple ResultSet made of one table type //CallStoredProcSimpleCase(myContext); //DEMO9: Using STORED PROC. Complex ResultSet made of various table type //CallStoredProcComplexCase(myContext); Console.WriteLine("\nDone..."); Console.ReadLine(); } catch (Exception e) { Console.WriteLine("\n Problems..." + e.Message); Console.ReadLine(); }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
10
}// main //-------------------------------------------------------------------------------------- public static void ShowMaleEmployees(CompanyLinqDataContext myContext) { var query1 = from e in myContext.EMPLOYEEs where e.sex == 'M' select e; foreach (EMPLOYEE emp in query1) { Console.WriteLine("{0} \t {1} {2}", emp.ssn, emp.fname, emp.lname); } }// ShowMaleEmployees // ---------------------------------------------------------------------- public static void ShowEmployeesProjects1(CompanyLinqDataContext myContext) { // for each employee list his/her projects // solution is based on (brute force) nested loops var query2e = from e in myContext.EMPLOYEEs select e; foreach (EMPLOYEE eRec in query2e) { Console.WriteLine("{0} {1}", eRec.ssn, eRec.lname); // find the assignments of the current employee var query2w = from w in myContext.WORKS_ONs where w.essn == eRec.ssn select w; foreach (WORKS_ON wRec in query2w) { // find the (single) project description of each assignment var query2p = (from p in myContext.PROJECTs where p.pnumber == wRec.pno select p).Single(); Console.WriteLine("\t{0} {1} {2}\t{3}", wRec.essn, wRec.pno, query2p.pname, wRec.hours); } } }// ShowEmployeesProjects1 // ---------------------------------------------------------------------- public static void ShowEmployeesProjects2(CompanyLinqDataContext myContext) { // for each employee list his/her projects // solution is based on (intelligent) join operations var query3 = from e in myContext.EMPLOYEEs from w in myContext.WORKS_ONs from p in myContext.PROJECTs where (e.ssn == w.essn) && (w.pno==p.pnumber) select new { e.ssn, e.lname, w.essn, w.pno, w.hours, p.pname }; foreach (var ewp in query3) { Console.WriteLine("{0} {1} Proj: {2} {3} Hours: {4} ", ewp.ssn, ewp.lname, ewp.pno, ewp.pname, ewp.hours); } }// ShowEmployeesProjects2 // ---------------------------------------------------------------------- public static void InsertSingleAssignment(CompanyLinqDataContext myContext) { // use Server Explorer. Create a Query to inspect assignments of 123456789 // (currently working on projects 1 and 2) // place 123456789 on project 3 for 1 hour WORKS_ON wRec = new WORKS_ON { essn = "123456789", pno = 3, hours = 1 }; myContext.WORKS_ONs.InsertOnSubmit(wRec); myContext.SubmitChanges();
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
11
// use Server Explorer to inspect employee's work-load } // InsertSingleAssignment // ---------------------------------------------------------------------- public static void InsertMultipleAssignments(CompanyLinqDataContext myContext) { // use Server Explorer to see entries of 123456789 in WORKS_ON // create a list of assignments for emp 123456789 List<WORKS_ON> wList = new List<WORKS_ON>(); WORKS_ON w1 = new WORKS_ON(){ essn="123456789", pno=10, hours=1}; WORKS_ON w2 = new WORKS_ON(){ essn="123456789", pno=20, hours=1}; WORKS_ON w3 = new WORKS_ON(){ essn="123456789", pno=30, hours=1}; wList.Add(w1); wList.Add(w2); wList.Add(w3); myContext.WORKS_ONs.InsertAllOnSubmit(wList); myContext.SubmitChanges(); // use Server Explorer to see additions made to 123456789's workload }//InsertMultipleAssignments // ---------------------------------------------------------------------- public static void DeleteSingleAssignment(CompanyLinqDataContext myContext) { // use Server Explorer. Create a Query to inspect assignments of 123456789 // (currently working on projects 1, 2, 3, 10, 20, 30) // removing employee from project 3; var wRec = myContext.WORKS_ONs.Single( w => (w.essn == "123456789")&&(w.pno==3)); myContext.WORKS_ONs.DeleteOnSubmit(wRec); myContext.SubmitChanges(); } // ---------------------------------------------------------------------- public static void DeleteMultipleAssignments(CompanyLinqDataContext myContext) { // removing employee 123456789 from projects 10, 20, 30 // observe the use of DeleteAllOnSubmit to get rid of the list // (instead of DeleteOnSubmit used to eliminate a single instance) var assignments = (from w in myContext.WORKS_ONs where (w.pno >= 3) && ( w.essn =="123456789") select w); myContext.WORKS_ONs.DeleteAllOnSubmit(assignments); myContext.SubmitChanges(); }// DeleteMultipleAssignments // ---------------------------------------------------------- public static void CallStoredProcSimpleCase(CompanyLinqDataContext myContext) { // Calling a StoredProc that returns rows from a single table // use Server Explorer to write the following MSSQL proc. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * ALTER PROCEDURE dbo.GetProjectsByDept ( @theDeptNo int ) AS SET NOCOUNT ON select p.* from Project p where p.dnum = @theDeptNo; RETURN * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** */ // Open the Object-Relational Designer window // Drag the icon representing in the Server Explorer the // procedure. Drop it on the right-side panel (Methods) // Right-Click on the procedure to display a pop-up window // from which we choose PROPERTIES
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
12
// On the property panel select RETURN TYPE and choose // PROJECT as the type to be made by the stored-proc // using anonymous type // var myProducts = myContext.GetProjectsByDept(5); // equivalent strongly-typed statement is IEnumerable<PROJECT> myProducts = myContext.GetProjectsByDept(5); foreach(var p in myProducts) { Console.WriteLine("{0} {1} {2}",p.pnumber, p.pname, p.dnum); } }//CallStoredProcSimpleCase // ---------------------------------------------------------- public static void CallStoredProcComplexCase(CompanyLinqDataContext myContext) { // Calling a StoredProc that returns rows from various tables // or returns a value made by a function (not a table type) // use Server Explorer to write the following MSSQL proc. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * ** * * * * * * ALTER PROCEDURE GetName2 (@aSSN int, @answer nvarchar(100) output ) as BEGIN -- Returns salutation + full-name of given employee DECLARE @gender nvarchar(2) set @answer = ' ' select @gender = sex from employee where ssn = @aSSN; if @@rowcount = 0 RETURN @answer; select @answer = (fname + ' ' + lname) from employee where ssn = @aSSN; if @gender = 'F' set @answer = 'Ms. ' + @answer else set @answer = 'Mr. ' + @answer; RETURN 0 END; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ** */ // Open the Object-Relational Designer window // Drag the icon representing the proc from the Server // Explorer. Drop it on the right-side panel (Methods) // Calling a stored Function to get emp's full name String fullName = ""; var myResult = myContext.GetName2(123456789, ref fullName); Console.WriteLine("{0} ", fullName ); // Calling a stored proc returning rows from various tables // use Server Explorer to enter the folowing MSSQL procedure // test it. Drag to Object-Relational Designer right panel. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ALTER PROCEDURE dbo.GetEmpNameProjectName ( @theDno int ) AS select e.ssn, e.lname, p.pname, w.hours from employee e, project p, works_on w where e.ssn = w.essn and w.pno = p.pnumber and e.dno = @theDno; RETURN * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * */ Console.WriteLine("\nEmployees in Dept 5"); var myMixedResults = myContext.GetEmpNameProjectName(5); foreach (var ep in myMixedResults) { Console.WriteLine("{0} {1} {2} {3}", ep.ssn, ep.lname, ep.pname, ep.hours);
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
13
} }//CallStoredProcComplexCase }// program }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
14
Output
123456789 John Smith
222333444 Inigo Montoya
333445555 Franklin Wong
666884444 Ramesh Narayan
888665555 James Borg
987987987 Ahmad Jabbar
123456789 Smith
123456789 1 32.5 ProductX
123456789 2 7.5 ProductY
222333444 Montoya
333445555 Wong
333445555 1 1.0 ProductX
333445555 2 10.0 ProductY
333445555 10 10.0 Computerization
333445555 20 10.0 REORGANIZATION
453453453 English
453453453 1 20.0 ProductX
453453453 2 20.0 ProductY
666884444 Narayan
666884444 3 40.0 PRODUCTZ
888665555 Borg
888665555 20 0.0 REORGANIZATION
987654321 Wallace
987654321 20 15.0 REORGANIZATION
987654321 30 20.0 Newbenefits
987987987 Jabbar
987987987 10 35.0 Computerization
987987987 30 5.0 Newbenefits
999887777 Zelaya
999887777 10 10.0 Computerization
999887777 30 30.0 Newbenefits
123456789 Smith Proj: 1 ProductX Hours: 32.5
123456789 Smith Proj: 2 ProductY Hours: 7.5
333445555 Wong Proj: 1 ProductX Hours: 1.0
333445555 Wong Proj: 2 ProductY Hours: 10.0
453453453 English Proj: 1 ProductX Hours: 20.0
453453453 English Proj: 2 ProductY Hours: 20.0
666884444 Narayan Proj: 3 PRODUCTZ Hours: 40.0
Done...
Query1
Query2
Query3
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
15
After INSERT operations (Using Server Explorer | New Query)
After DELETE records
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
16
Using Stored-Procedures
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
17
PART 2. Web Apps Using LINQ-to-SQL
Exploring the LinqDataSource Class
1. Create an ASP.NET Web Application (WebLinq2Sql1).
2. Right-click on the application. Add | New Item… | Linq to Sql Classes. Name it: COMPANY.dbml
3. Click on Server Explorer. Drag-drop on Object-Relational-Designer tables: EMPLOYEE, WORKS_ON,
PROJECT. Save the design.
4. Use Solution Explorer. Click on the DEFAULT.ASP (Design) page. Click on ToolBox > Data. Drag-Drop a
GridView on the ASP form.
5. Select the code-behind page of the Default.asp page. Modify the Page_Load method as follows:
protecetd void Page_Load(object sender, EventArgs e) { COMPANYDataContext myContext = new COMPANYDataContext(); var query1 = from emp in myContext.EMPLOYEEs where ((emp.sex == 'F') || (emp.dno == 5)) select emp; GridView1.DataSource = query1; GridView1.DataBind(); }
6. Execute the application. It will retrieve a list of employees who either are ladies or work for dept. no. 5.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
18
Version 2. A custom list of attributes – Using the new {…} clause
You may customize the output list produced by the LINQ expression and consequently adjust the GridView‟s
datasource. For instance, we may request the LINQ expression to project only the employee‟s SSN, first and last name,
and dept no. Similarly you may modify the aesthetics of this app by clicking on the gridView‟s menu button (top-
right) and selecting “Auto Format…”. Change to any of the predefined layouts, here we choose “Colorful”.
The previous example should be modified as follows:
protected void Page_Load(object sender, EventArgs e) { COMPANYDataContext myContext = new COMPANYDataContext(); var query1 = from emp in myContext.EMPLOYEEs where ((emp.sex == 'F') || (emp.dno == 5)) select new {emp.ssn, emp.fname, emp.lname, emp.sex, emp.dno}; GridView1.DataSource = query1; GridView1.DataBind(); }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
19
Web Demo 3. Adding a DropDown list & using its values to select data for the DataGrid.
Now we proceed to create a more complex web app. From a drop-down list the user will select a project and a
GridView will show all the employees affiliated to the selected project.
The key steps to the solution are as follows:
(a) Create a new web application call it WebLinq3. Add a “Linq to SQL class” to the application. Use the Server
Explorer to drag-drop the EMPLOYEE, WORKS_ON, and PROJECT tables to the Object-Designer Surface. Use
the Solution Explorer to show the Default.asp page. From the Toolbox drag-drop a Drop-Down list and a
GridView.
(b) Important! Change the AutoPostBack property of the drop-down list to true.
(c) the DataSource, and DataValueField attributes of the Drop-Down list will be a LINQ expression that retrieves
all the projects, and the project name (Pname) field respectively.
(d) The value DropDownList1.SelectedValue will be used in phrasing the LINQ expression producing Employees.
These changes will be detected with the .SelectedIndexChanged event of the drop-down list. The result of the
second LINQ query is the DataSource that feeds the GridView.
The final solution is
using System;
using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; namespace WebLinq3 { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // setting the drop-down list to show project names. Do it when the // page is loaded the first time (not as a result of a client's postbak) if (!Page.IsPostBack) { COMPANYDataContext myContext = new COMPANYDataContext(); var query1 = from pRec in myContext.PROJECTs select pRec; DropDownList1.DataSource = query1; DropDownList1.DataValueField = "Pname"; DropDownList1.DataBind(); } }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
20
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e) { COMPANYDataContext myContext = new COMPANYDataContext(); // retrieving employees working in selected project var query2 = from eRec in myContext.EMPLOYEEs from wRec in myContext.WORKS_ONs from pRec in myContext.PROJECTs where ((pRec.pname == DropDownList1.SelectedValue) && (pRec.pnumber == wRec.pno) && (wRec.essn == eRec.ssn)) select new { eRec.ssn, eRec.fname, eRec.lname, eRec.dno }; GridView1.DataSource = query2; GridView1.DataBind(); } } }
NOTE.
Must change the DropDown list
property AutoPostBack to true.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
21
Web Demo4. Complex Projection of Attributes from a Table.
In this new web-app we will list all projects and the total hours & employees working on them. Aggregation will be
used to compute sum and count values. We will „nicely‟ rename and format output columns. This is called „Shaping
Results‟.
1. Create a new web app call it: WebLinq2Sql4
2. Add | New items… | Linq to Sql classes | name it COMPANY.
3. Click on Server Explorer. Drag PROJECT, WORKS_ON, and EMPLOYEE tables to the Object-Relational
Designer.
4. Place a GridView control on the Default.asp page.
5. Add the following code-behind
protected void Page_Load(object sender, EventArgs e) { COMPANYDataContext myContext = new COMPANYDataContext(); var query1 = from w in myContext.WORKS_ONs from p in myContext.PROJECTs where (w.pno == p.pnumber) group w by new { w.pno, p.pname } into g select new { ProjID = g.Key.pno, Name = g.Key.pname, TotalHours = (decimal?)g.Sum(wr => wr.hours), TotalEmps = (int?)g.Count() }; GridView1.DataSource = query1; DataBind(); }
Note:
1. The expression (decimal?) is a cast on a nullable attribute (if null then empty).
2. .Key is an attribute produced by the GroupBy clause.
3. Observe multiple groupBy fields and selected fields made of aggregations.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
22
Web Demo5. Displaying n rows per page (Using a GridView and Skip( ) and Take( ) Methods
1. Create a new web project to show all records from the WORKS_ON table in a GridView.
2. Add a Hyperlink control to the asp page.
3. Enter the following code-behind.
using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq; namespace WebLinq2Sql2 { public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { // we add to the ASP Request.Path a variable (rowNumber) and // a value (3, 6, 9...). This pair is sent from the client to the server // each time the page visits the server int rowNumber = Convert.ToInt32( Request.QueryString["rowNumber"]); String nextNumber = (rowNumber + 3).ToString(); HyperLink1.NavigateUrl = Request.Path + "?rowNumber=" + nextNumber; MyPopulateGrid(rowNumber); } private void MyPopulateGrid(int rowNumber) { COMPANYDataContext myContext = new COMPANYDataContext(); // retrieve assignments var query1 = from w in myContext.WORKS_ONs orderby w.essn, w.pno select w; // notice the use of the Skip and Take methods GridView1.DataSource = query1.Skip(rowNumber).Take(3); DataBind(); } } }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
23
Web Demo 6. DeclarativeASP.NET Databinding Using a LinqDataSource
This app will display/update table data without coding. Setup is made via declarative statements affecting the GUI,
DataSource, and ASP elements. Data will be displayed in a GridView from where the user will be able to insert, delete,
and modify any Employee row.
1. Create a new ASP app.
2. Create a new Entity-Model: Add | New item…| Linq to Sql classes. Call new model: CompanyEntityModel.
3. Use Server Explorer. Drag-drop EMPLOYEE and DEPARTMENT tables.
4. Save all. Right-Click on the project‟s name to Build all the elements !!!
5. Place a GridView on the Default.asp (design view) page. Click on the top-right arrow-menu button to bring
the „GridView Tasks‟ dialog box.
6. Click the dropdown control Choose DataSource and select <New data source…>. Name it:
DepEmpLinqDataSource.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
24
7. CRITICAL. A sequence of Dialog boxes will appear. On the first one select the context object:
In this example we want to enforce the following rule:
An employee’s salary should not be higher than her direct supervisor’s salary.
Steps:
1. Create a new console application (ConLinq2Sql7). Add a “LINQ to SQL class”, call it CompanyEmp. Set the
Entity-Model diagram, holding the Employee table.
2. Use the Server Explorer to isolate a pair of employees that we will use to test the app. In our case observe
employees Smith and Wong. Their salaries are 30K and 40K respectively. Notice that Mr. Wong supervises
Mr. Smith.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
31
3. Enter the following code in the Program.cs file
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConLinq2Sql7 { class Program { static void Main(string[ ] args) { // wanting to enforce rule: // employees can not make more than their supervisors CompanyEmpDataContext myContext = new CompanyEmpDataContext(); // obtain Mr. Smith's record he make $30K // (we know his supervisor Mr. Wong makes $40K.) var emp = (from e in myContext.EMPLOYEEs where e.lname.Equals("Smith") select e).Single(); try { // try this first to test the OnValidate method added to the // extension of the EMPLOYEE class. emp.salary = 50000; //should trow exception // try this later to test rule attached to OnbdateChange method // emp.bdate = DateTime.Now.AddDays(1); myContext.SubmitChanges(); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.WriteLine("Done..."); Console.ReadLine(); } } }
4. Execute the program. Use Server Explorer to inspect the EMPLOYEE table.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
32
Observe that Smith‟s salary was changed to 50K (this is higher than Wong‟s – which is in violation to the
company‟s rules- but at this point nothing prevents it from happening!).
5. Reset Smith‟s salary to 30K (use Server Explorer > Show Table Data > retype Salary 30000).
6. Now, to enforce the business rule indicated earlier we could either write a database trigger or locally put
code in the Entity-Model to perform custom validation. We will explore the second option.
7. Enhance the EMPLOYEE definition (originally placed in CompanyEmp.designer.dbml which is part of
CompanyEmp.dbml) by adding a new (partial) class to the project. The new fragment will include the
validation logic (in the onValidate hook). Enter the following code
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConLinq2Sql7 { // This fragment extends the EMPLOYEE class definition (originally placed // in CompanyEmp.designer.dbml which is part of CompanyEmp.dbml). // Here we add a validation method to attend the "update" operation public partial class EMPLOYEE { partial void OnValidate(System.Data.Linq.ChangeAction action) { CompanyEmpDataContext myContext = new CompanyEmpDataContext(); // you should add logic for the: insert & delete cases // here we just take care of update operations if (action == System.Data.Linq.ChangeAction.Update) { //find the supervisor's record var super = (from s in myContext.EMPLOYEEs where s.ssn == this.superssn select s).Single(); //is this employee making more than her supervisor? if (this.salary > super.salary) { String errorMsg = String.Format( "VIOLATION: {0} has salary > than supervisor {1}", this.lname, super.lname); throw new Exception(errorMsg); } } }//OnValidate // Observation: // changes to specific fields can be tested using the corresponding // OnFIELDChanged() method. For example OnbdateChange follows partial void OnbdateChanged() { if (this.bdate > DateTime.Now) { throw new Exception("Invalid Birthdate"); } }//OnbdateChanged }//EMPLOYEE }
8. Execute the program (make sure Smith‟s salary initially is $30K). You should see the output:
VIOLATION: Smith has salary > than supervisor Wong
Done...
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
33
9. Modify Program.cs. Replace the line emp.salary = 50000; with emp.salary = 39000; this should not raise the
salary custom rule violation. Uncomment the birthdate assignment.
emp.salary = 39000; //should NOT trow exception
emp.bdate = DateTime.Now.AddDays(1); //to test birthdate change
10. The change in birth date raises an exception in the onbdateCanged( ) method.
Invalid Birthdate Done...
11. Neither field salary nor bdate is changed.
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
34
Demo 2. Using Stored Procedures for Create, Retrieve, Update, Delete (CRUD) operations
The goal of this demo is to show how to replace the default LINQ CRUD operations for user-defined methods.
1. Create a new project: ConLinq2SqlPart4.
2. Use Server Explorer to enter three MS-SQL-SERVER stored procedures to insert, delete, and update
WORKS_ON records. The server-side T-SQL procedures are given below
myInsertWorksOn myDeleteWorksOn myUpdateWorksOn CREATE PROCEDURE dbo.myInsertWorksOn ( @essn char(9), @pno int, @hours decimal(5,1) ) /* inserting a new assignment into WORKS_ON table */ AS insert into WORKS_ON (essn, pno, hours) values ( @essn, @pno, @hours ) RETURN
CREATE PROCEDURE dbo.myDeleteWorksOn ( @essn char(9), @pno int ) /* deleting an assignment from the WORKS_ON table */ AS delete WORKS_ON where (essn = @essn) and (pno = @pno) RETURN
CREATE PROCEDURE dbo.myUpdateWorksOn ( @essn char(9), @pno int, @hours decimal(5,1) ) /* updating an assignment in the WORKS_ON table */ AS update WORKS_ON set hours = @hours where (essn = @essn) and (pno = @pno) RETURN
3. Create the Assignments Entity-Model by dropping the WORKS_ON table to the OR-designer. Drag to the
OR-Designer Methods Panel each of the server-side stored procedures
4. Click on the WORKS_ON entity and bring the property page. Look for the methods to insert, delete,
update. Individually change their default value “Use runtime” to each of the methods created above. For
instance when changing the delete method a Configure Behavior windows appears. Select the option
Customize, use the dropdown list to choose the stored procedure myDeleteWorksOn. Click on Apply.
Repeat the process for the insert and update operations. This will update the entity‟s property page (see
image below)
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
35
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos
36
5. Ready to test. Enter the following code under Program.cs.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Linq2SqlPart4 { class Program { static void Main(string[] args) { // tesing the custom-made UPDATE procedure using (ASSIGNMETSDataContext myContext = new ASSIGNMETSDataContext()) { var task = (from w in myContext.WORKS_ONs where (w.essn == "123456789") && (w.pno == 1) select w).Single(); Console.WriteLine("BEFORE hours {0}", task.hours); task.hours = 60; myContext.SubmitChanges(); } using (ASSIGNMETSDataContext myContext = new ASSIGNMETSDataContext()) { var task = (from w in myContext.WORKS_ONs where (w.essn == "123456789") && (w.pno == 1) select w).Single(); Console.WriteLine("AFTER hours {0}", task.hours); } // testing custom-made INSERT method using (ASSIGNMETSDataContext myContext = new ASSIGNMETSDataContext()) { try { // place 123456789 on project 3 for 1.8 hours WORKS_ON wRec = new WORKS_ON { essn = "123456789", pno = 3, hours = (decimal)1.8 }; myContext.WORKS_ONs.InsertOnSubmit(wRec); myContext.SubmitChanges(); Console.WriteLine("AFTER Inserting"); } catch (Exception ex) { Console.WriteLine("Problems inserting\n" + ex.Message); } }
Cleveland State University CIS611 – LINQ to SQL Lecture Notes – Prof. V. Matos