V 1.0 OE-NIK HP 1 Advanced Programming Database access layers DbConnection/DbReader (Not required!) DataSet (Not required!) LINQ / Entity Framework
V 1.0 OE-NIK HP 2 Advanced Programming Database access layers DbConnection/DbReader (Not required!) DataSet (Not required!) LINQ / Entity Framework
V 1.0 SQL Server / SQL Express / LocalDB MSSQL: typically used by small and medium-sized companies („fully ACID compliant”) (Oracle, IBM, MSSQL, Sybase, Teradata ; Free: MySQL, PostgreSQL, MariaDB) Earlier VS versions (x<2012): a smaller version of the database server was installed alongside the developer environment (SQL Express) : max 10gb/database, max 1 physical cpu, max 1gb ram (Data Source=.\SQLEXPRESS) Available since VS 2010, default since VS 2012: LocalDB, instead of a service an on-demand library that uses a database file (similar to sqlite (Data Source = (localdb)\v11.0) ) –We will use this (in Windows authentication mode) –The computers have MSSQL 2012 Express as well, if needed OE-NIK HP 3
V 1.0 DbConnection vs DataSet vs LINQ Various abstraction layers DbConnection –The most basic access layer, pure SQL, string SQL commands, object array result-set DataSet –Above the SQL layer; a strongly-typed and GUI-centered layer; strongly typed methods for the various operations DB-LINQ / Entity Framework –Above the SQL layer; a strongly-typed and data-centered, well organized MVC/ORM (Object Relational Mapping) layer: tables are nothing more than collections of entities; special queries Basic operations: Connect/initialization; insert; update; delete; query; connection with GUI elements OE-NIK HP 4
V 1.0 OE-NIK HP 5 Advanced Programming Database access layers DbConnection/DbReader (Not required!) DataSet (Not required!) LINQ / Entity Framework
V 1.0 ADO.NET: DbConnection/DbReader Old-fashioned data access (not MVC / ORM – connected mode) Advantage: fast, simple Cons: hard to modify and to change technology/storagene, must handle if the connection is lost, hard to manage the types Different implementations for different database servers Common base classes for the common operations –Connection: DbConnection –SQL/RPC execution: DbCommand –Read SQL results: DbDataReader Specific descendant classes for the different database servers: –SqlConnection (MSSQL System.Data.SqlClient), MySqlConnection (MySQL MySql.Data.MySqlClient), NpgsqlConnection (PostgreSQL - Npgsql), OracleConnection (Oracle System.Data.OracleClient) OE-NIK HP 6
V Initialization string connStr Source=.\SQLEXPRESS;Initial Catalog=nikdb;User ID=nik;Password=kin"; SqlConnection conn; private void button15_Click(object sender, EventArgs e) { conn = new SqlConnection(connStr); conn.Open(); MessageBox.Show("CONNECTED"); } OE-NIK HP 7
V Initialization (MySQL, Postgre) case server_type.mysql: FConnStr = "server = " + FServer + ";\n" + "database = " + FDb + ";\n" + "user id = " + FUser + ";\n" + "password = " + FPass + ";\n"; FDatabase_Connection = new MySqlConnection(FConnStr); break; case server_type.postgre: FConnStr = "server = " + FServer + ";\n" + "database = " + FDb + ";\n" + "user id = " + FUser + ";\n" + "password = " + FPass + ";\n"; FDatabase_Connection = new NpgsqlConnection(FConnStr); break; OE-NIK HP 8
V Initialization (Oracle) case server_type.oracle: FConnStr = "data source = " + FServer + ";\n" + "user id = " + FUser + ";\n" + "password = " + FPass + ";\n"; FDatabase_Connection = new OracleConnection(FConnStr); break; OE-NIK HP 9
V INSERT private void button18_Click(object sender, EventArgs e) { SqlCommand comm = new SqlCommand("insert into EMP (ENAME, MGR, DEPTNO, EMPNO) values ('BILL', NULL, 20, 1000)", conn); SqlDataReader reader=comm.ExecuteReader(); MessageBox.Show(reader.RecordsAffected.ToString()); reader.Close(); } OE-NIK HP 10
V UPDATE private void button18_Click(object sender, EventArgs e) { SqlCommand comm = new SqlCommand("update EMP set ENAME='JOE' where EMPNO=1000", conn); SqlDataReader reader=comm.ExecuteReader(); MessageBox.Show(reader.RecordsAffected.ToString()); reader.Close(); } OE-NIK HP 11
V DELETE private void button18_Click(object sender, EventArgs e) { SqlCommand comm = new SqlCommand("delete from EMP where empno=1000", conn); SqlDataReader reader=comm.ExecuteReader(); MessageBox.Show(reader.RecordsAffected.ToString()); reader.Close(); } OE-NIK HP 12
V SELECT private void button14_Click(object sender, EventArgs e) { listBox1.Items.Clear(); SqlCommand comm = new SqlCommand("select * from EMP where sal>=3000 order by ename", conn); SqlDataReader reader = comm.ExecuteReader(); while (reader.Read()) { listBox1.Items.Add(reader["ENAME"].ToString()); } reader.Close(); } OE-NIK HP 13
V BIND private void button13_Click(object sender, EventArgs e) { dataGridView1.DataSource = null; dataGridView1.Rows.Clear(); dataGridView1.Columns.Clear(); dataGridView1.AllowUserToAddRows = false; SqlCommand comm = new SqlCommand("select * from EMP order by ename", conn); SqlDataReader reader = comm.ExecuteReader(); while (reader.Read()) { [LOAD GRIDVIEW ROWS] } reader.Close(); } OE-NIK HP 14
V BIND – LOAD GRIDVIEW ROWS if (dataGridView1.Columns.Count == 0) { for (int i = 0; i < reader.FieldCount; i++) { string coltext = reader.GetName(i).ToLower(); dataGridView1.Columns.Add(coltext, coltext); } dataGridView1.Rows.Add(); int rowid = dataGridView1.Rows.Count - 1; for (int i = 0; i < reader.FieldCount; i++) { dataGridView1.Rows[rowid].Cells[i].Value = reader[i].ToString(); } OE-NIK HP 15
V 1.0 OE-NIK HP 16 Advanced Programming Database access layers DbConnection/DbReader (Not required!) DataSet (Not required!) LINQ / Entity Framework
V 1.0 ADO.NET: DataAdapter/DataSet/DataTable Old-fashioned data access (not MVC), disconnected mode Advantages: no need for writing specific SQL commands, simpler connection to GUI controls Cons: hard to modify and change between technologies/storages –Typically only works with MSSQL (or: via.NET connector or standardized ODBC drivers: might be unstable/buggy) Uses automatically generated, table-dependent, strongly typed classes (~200KB is normal for a two-table database) After auto-generation, specific classes for tables/fields: –BindingSource: Data source connection for the controls –TableAdapter: Table description, database-connection, operations –DataSet: database representation, unification of tables OE-NIK HP 17
V 1.0 Creating a DataSet We need the Server explorer (in Express Edition: Database Explorer) and the Data Sources (shift+alt+d) windows Server explorer: Add connection –Type: Microsoft SQL Server –Server Name:.\SQLEXPRESS, SQL Server Authentication, User: nik, Pass: kin, Save password, Database name: nikdb Data sources: Add new data source –Database / DataSet –Select connection, „Include sensitive data” –„Save connection string to the application file”, select tables After this, we can simply drag & drop the table from the Data sources window into the form, and the application is ready OE-NIK HP 18
V Initialization private void button5_Click(object sender, EventArgs e) { eMPTableAdapter.Fill(nikdbDataSetVariable.EMP); MessageBox.Show("CONNECTED"); } OE-NIK HP 19
V INSERT private void button8_Click(object sender, EventArgs e) { DataRow ujsor = nikdbDataSetVariable.EMP.NewRow(); //NewEmpRow() is also useable ujsor["ENAME"] = "BILL"; ujsor["MGR"] = DBNull.Value; ujsor["DEPTNO"] = 20; ujsor["EMPNO"] = 1000; nikdbDataSetVariable.EMP.Rows.Add(ujsor); eMPTableAdapter.Update(nikdbDataSetVariable); MessageBox.Show("DONE"); } OE-NIK HP 20
V UPDATE private void button7_Click(object sender, EventArgs e) { DataRow dr = nikdbDataSetVariable.EMP.Rows[0]; dr.BeginEdit(); dr["ENAME"] = "JOE"; dr.EndEdit(); nikdbDataSet valtozas=(nikdbDataSet)nikdbDataSetVariable. GetChanges(DataRowState.Modified); if (valtozas.HasErrors) { nikdbDataSetVariable.RejectChanges(); } else { nikdbDataSetVariable.AcceptChanges(); eMPTableAdapter.Update(valtozas); } OE-NIK HP 21
V DELETE private void button6_Click(object sender, EventArgs e) { DataRow dr = nikdbDataSetVariable.EMP.Rows[0]; dr.Delete(); nikdbDataSetVariable.AcceptChanges(); eMPTableAdapter.Update(nikdbDataSetVariable); } DataRow dr = nikdbDataSetVariable.EMP.Select("empno=1000")[0]; // THIS IS NOT THE LINQ EXTENSION METHOD, ONLY IT HAPPENS TO HAVE THE SAME NAME! OE-NIK HP 22
V SELECT private void button12_Click(object sender, EventArgs e) { listBox1.Items.Clear(); foreach (DataRow dr in nikdbDataSetVariable.EMP.Select("sal>=3000")) { listBox1.Items.Add(dr["ENAME"].ToString()); } OE-NIK HP 23
V BIND private void button11_Click(object sender, EventArgs e) { dataGridView1.Columns.Clear(); dataGridView1.Rows.Clear(); dataGridView1.DataSource = null; //dataGridView1.DataSource = nikdbDataSetVariable.EMP; dataGridView1.DataSource = eMPBindingSource; } OE-NIK HP 24
V 1.0 OE-NIK HP 25 Advanced Programming Database access layers DbConnection/DbReader (Not required!) DataSet (Not required!) LINQ / Entity Framework
V 1.0 Entity Framework (LINQ: to SQL / to Entities) LINQ to SQL –Older, similar syntax but COMPLETELY DIFFERENT APPROACH! –Supports only direct mapping and only MSSQL dialect –„Rapid development” ??? (or: “should not have been released”) –Generate classes: Project/Add Class/LINQ to SQL classes ADO.NET Entity Framework (LINQ to Entites) –Newer, full ORM, supports N:M relations –Can work with other dialects (Oracle, MySQL, Postgres...) –Generate clases: Data sources / Add new data source / Database / Entity Data Model –Newer VS versions: Project / Add New Item / Data / ADO.NET Entity Data Model OE-NIK HP 26
V 1.0 Entity model creation alternatives Code First: first write the classes, then map/generate the database (POCO classes!) Database/SQL First: auto-generate the classes from an already existing database Model First (OBSOLETE): We can „draw” the data model (= class diagram) ( ) OE-NIK HP 27
V 1.0 Entity Framework versions EF1 = EF3.5 .NET 3.5 EF4 .NET 4 „POCO support, lazy loading, testability improvements, customizable code generation and the Model First workflow” EF4.1 „first to be published on NuGet. This release included the simplified DbContext API and the Code First workflow” Jó! EF4.3 „Code First Migrations” We have a working ORM! EF5, EF6, EF 6.1 EF7: RC ; final = ??? („EF7 introduces some significant changes and improvements over EF6.x. Because EF7 is based on a new core, the features from EF6.x do not automatically carry over into EF7. For this reason, EF6.x may still be the most suitable release for many applications”) Updateable (with NuGet, we use the built-in version) OE-NIK HP 28
V 1.0 Creating LocalDB In-Solution –Project / Add New Item / Service-based Database (this will be an SQL server file. Local Database: SQL server compact file) –We can use both, service-based is preferred: EmpDept.mdf –First we load the data, then we generate the classes In-Profile –Server Explorer -> Right click (Data Connections) -> Add Connection ( Microsoft SQL Server +.Net provider for SQL Server ) –Server name = (localdb)\v11.0, Database name = EMPDEPT –"Database does not exists. Attempt to create?" –We could follow the „Create New SQL Server Database” button, with similar steps OE-NIK HP 29
V 1.0 Load the data Right click on the new DB, new query, copypaste everything from the creator SQL, Execute, then the query window can be closed (right click on new DB/tables, refresh: tables should be shown) Project, Add new Item, ADO.NET Entity Data Model ; Generate from database ; select the MDF file + save connection settings ; EF6.0 ; check both tables + Model namespace = EmpDeptModel Depending on security settings: Template can harm your computer, click ok to run... ( ) Result: automatically generated classes (just like with the DataSet), but these are simpler (POCO) or generic classes ~30KB for the two-table database OE-NIK HP 30
V Initialization ED = new EmpDeptEntities(); Console.WriteLine("Connect OK"); var reszleg = ED.DEPT.First(); Console.WriteLine(reszleg.DNAME); var dolg = from dolgozo in ED.EMP where dolgozo.ENAME.Contains("E") select dolgozo; Console.WriteLine(dolg.Count()); OE-NIK HP 31
V INSERT var worker = new EMP() { ENAME = "BILL", MGR = null, DEPTNO = 20, EMPNO = 1000 }; ED.EMP.Add(worker); // used to be: AddObject ED.SaveChanges(); Console.WriteLine("Insert OK"); OE-NIK HP 32
V UPDATE var worker = ED.EMP.Single(x => x.EMPNO == 1000); worker.ENAME = "JOE"; ED.SaveChanges(); Console.WriteLine("Update OK"); OE-NIK HP 33
V DELETE var worker = ED.EMP.Single(x => x.EMPNO == 1000); ED.EMP.Remove(worker); // used to be: DeleteObject ED.SaveChanges(); Console.WriteLine("Delete OK"); OE-NIK HP 34
V SELECT string s = "", sep=""; foreach (var w in ED.EMP.Where(worker => worker.SAL >= 3000)) { s += sep + w.ENAME; sep = ","; } Console.WriteLine(s); Console.WriteLine( string.Join(";", ED.EMP.Select(x => x.ENAME)) ); OE-NIK HP 35
V BIND { dataGridView1.Columns.Clear(); dataGridView1.Rows.Clear(); dataGridView1.ItemsSource = null; var workers = from w in NE.EMP orderby w.ENAME select w; dataGridView1.ItemsSource = workers.ToList(); } Can be bound through DataContext ItemsSource can only be workers.ToList() or the full table (ED.EMP.Local) after an ED.EMP.Load() Data model vs view model vs communication don’t mix... OE-NIK HP 36
V JOIN var workers = from w in NE.EMP join d in NE.DEPT on w.DEPTNO equals d.DEPTNO select new { w.ENAME, w.SAL, d.DNAME }; OR with Lazy Loading: var workers = from w in NE.EMP select new { w.ENAME, w.SAL, w.DEPT.DNAME }; OE-NIK HP 37
V 1.0 Advantages of an ORM We have ZERO dialect-dependent SQL code We can switch dialect/server without modifying anything Instead of string-based SQL commands, we use a query syntax that is checked by the compiler Any error in a query will be detected at compile-time Instead of string concatenation (and string/object parameters) we use actual variables as query parameters Avoid SQL injection The query results are not generic anonymous type / object / associative array Instead: strongly typed value / instance / list of known types By placing an extra layer on top of an ORM layer, we can achieve total storage separation and easy testing Repository Pattern, Dependency Injection Pattern OE-NIK HP 38
V 1.0 Tables OE-NIK HP 39
V 1.0 Exercises 1.Add a „Service-Based Database” with the name EmpDept.mdf, fill this using the orademo.sql and then create the Entity classes! 2.Determine the average income for every department names (income = salary + commission)! 3.Determine the biggest department! 4.Increase the salary for the people in the job with the smallest sum salary. The job with the smallest sum should have the same sum as the job with the second to smallest sum; distribute the extra salary evenly amongst the workers! 5.Delete the workers who were hired in the 30 days after the hire date of the president! OE-NIK HP 40
V 1.0 OE-NIK HP 41 Sources
V 1.0 OE-NIK HP 42
43 OE-NIK HP