Haladó Programozás Adatbázis-elérési módszerek összehasonlítása Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel SQL server elérése Entity Framework módszerrel OE-NIK HP
Haladó Programozás Adatbázis-elérési módszerek összehasonlítása Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel SQL server elérése Entity Framework módszerrel OE-NIK HP
SQL Server / SQL Express / LocalDB MSSQL: tipikusan kis- és középvállalatok által használt adatbázis-kezelő szerver SQL Express: kisebb változat: max 10GB/database, max 1 CPU, max 1GB RAM Korábbi VS verziók (x<2012): SQL Express integrálva volt a fejlesztőeszköz telepítőjébe (Data Source=.\SQLEXPRESS) VS 2010 óta elérhető, VS 2012-től default: LocalDB (Data Source=(localdb)\v11.0) Szerver-szolgáltatás helyett igény szerint induló library, ami egy adatbázis-file-t használ Órán ezt használjuk A gépeken van MSSQL 2012 Express is, ha esetleg a projekthez kell MSSQL: aki akarja, az elmondja itt, hogy ez fully ACID compliant :P SQL Express = MS SQL kisebb változata (Oracle, IBM, MSSQL, Sybase, Teradata ; Free: MySQL, PostgreSQL, MariaDB) OE-NIK HP
DbConnection vs DataSet vs Entity Framework Különböző absztrakciós szintek DbConnection Alap SQL-szintű elérés, string SQL utasításokkal, object tömb eredményekkel DataSet Az SQL réteg fölé egy erősen típusos, GUI központú réteg kerül, a műveleteket típusos metódusok végzik Entity Framework Az SQL réteg fölé egy MVC elvű ORM (Object Relational Mapping) réteget helyezünk: a táblákat mint objektumok általános gyűjteményét kezeljük Alapvető műveletek: Kapcsolódás/inicializáció; beszúrás; módosítás; törlés; adatlekérés; GUI-hoz kapcsolás Az „Alapvető műveletek” listán fogunk mindegyik módszernél végigmenni OE-NIK HP
Haladó Programozás Adatbázis-elérési módszerek összehasonlítása Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel SQL server elérése Entity Framework módszerrel Ezeket LEHET BEMUTATÓZNI IS – 1 sqlconnection-ös parancs + a datasetnél wpf-ben mutasd meg, hogy hogy van OE-NIK HP
ADO.NET: DbConnection/DbReader „Kapcsolt” adatbázis-elérés (Connected Data-Access Architecture) Előny: gyors, egyszerű Hátrány: nehéz módosítani és technológiát/tárolási módszert váltani; kapcsolat elveszését kezelni kell A különböző adatbázis-szerverekhez különböző implementációk Közös ősosztályok a különféle feladatokhoz Adatbázis-kapcsolat: DbConnection SQL/RPC utasítás végrehajtása: DbCommand Utasítás eredményének beolvasása: DbDataReader Specifikus utódosztályok a különféle adatbázis-szerverekhez SqlConnection (MSSQL System.Data.SqlClient) MySqlConnection (MySQL MySql.Data.MySqlClient) NpgsqlConnection (PostgreSQL - Npgsql) OracleConnection (Oracle System.Data.OracleClient) Connected: bármilyen művelet végrehajtásához kapcsolódsz vagy folyamatosan életben tartod a kapcsolatod OE-NIK HP
1. Inicializálás string connStr = @"Data Source=(LocalDB)\v11.0;AttachDbFilename=path\to\empdept.mdf;Integrated Security=True;"; SqlConnection conn; private void button15_Click(object sender, EventArgs e) { conn = new SqlConnection(connStr); conn.Open(); MessageBox.Show("CONNECTED"); } OE-NIK HP
2. INSERT private void button18_Click(object sender, EventArgs e) { SqlCommand comm = new SqlCommand("insert into EMP (ENAME, MGR, DEPTNO, EMPNO) values ('BELA', NULL, 20, 1000)", conn); SqlDataReader reader=comm.ExecuteReader(); MessageBox.Show(reader.RecordsAffected.ToString()); reader.Close(); } OE-NIK HP
3. UPDATE private void button18_Click(object sender, EventArgs e) { SqlCommand comm = new SqlCommand("update EMP set ENAME='JOZSI' where EMPNO=1000", conn); SqlDataReader reader=comm.ExecuteReader(); MessageBox.Show(reader.RecordsAffected.ToString()); reader.Close(); } OE-NIK HP
4. 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
5. 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(); Cél: azon nevekkel feltölteni egy listboxot, akiknek a fizetése >= 3000 OE-NIK HP
6. Megjelenítés GUI-n 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()) [GRIDVIEW FELTÖLTÉSE] } reader.Close(); Adatkötés létrehozása: cél dataGridView-hoz csatolni az adattáblát. Értelemszerűen alacsonyszintű kapcsolat esetén nem lehetséges kézzel kell feltölteni Azt emeld ki, hogy nincs adatkötés. OE-NIK HP
6. Megjelenítés GUI-n - GRIDVIEW FELTÖLTÉSE 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
Haladó Programozás Adatbázis-elérési módszerek összehasonlítása Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel SQL server elérése Entity Framework módszerrel OE-NIK HP
ADO.NET: DataAdapter/DataSet/DataTable „Kapcsolat nélküli” adatbázis-elérés (Disconnected D-A. A.) Előny: nem kell konkrét SQL utasításokat írni, könnyebb adatkapcsolódás a GUI elemeihez Hátrány: nehéz módosítani és technológiát/tárolási módszert váltani; nagy memóriaigény Automatikusan generált, adatfüggő típusozott osztályok keletkeznek (~200KB teljesen normális méret egy két táblás adatbázishoz) Az osztályok legenerálása után egyedi osztályok vannak a táblákhoz/adatmezőkhöz: TableAdapter: az adatbázishoz való kapcsolatot építi fel, eredményeket olvas DataSet: az adatbázis reprezentációja BindingSource: adatforrás-kapcsolat az ablak felé Kapcsolat nélküli: NEM tart fenn folyamatos kapcsolatot, az adatbázist teljes egészében a memóriába húzza és ott tartja. Kapcsolódáskor viszi fel a db-be az addigi változtatásokat. OE-NIK HP
DataSet létrehozása Server explorer (Express Edition-ben: Database Explorer) és Data Sources (Shift+Alt+D) fül kell Server explorer: Adatbázis/connection létrehozása Későbbi dián részletezzük Data sources: Add new data source Database / DataSet Connection kiválasztása, „Include sensitive data” „Save connection string to the application file”, Táblák kiválasztása Ezután a DataSources-ból az ablakra egyszerűen ráhúzzuk a táblát, máris kész az alkalmazás OE-NIK HP
1. Inicializálás private void button5_Click(object sender, EventArgs e) { eMPTableAdapter.Fill(nikdbDataSetVariable.EMP); MessageBox.Show("CONNECTED"); } OE-NIK HP
2. INSERT private void button8_Click(object sender, EventArgs e) { DataRow ujsor = nikdbDataSetVariable.EMP.NewRow(); //NewEmpRow() is használható lenne ujsor["ENAME"] = "BELA"; ujsor["MGR"] = DBNull.Value; ujsor["DEPTNO"] = 20; ujsor["EMPNO"] = 1000; nikdbDataSetVariable.EMP.Rows.Add(ujsor); eMPTableAdapter.Update(nikdbDataSetVariable); MessageBox.Show("DONE"); } OE-NIK HP
3. UPDATE private void button7_Click(object sender, EventArgs e) { DataRow dr = nikdbDataSetVariable.EMP.Rows[0]; dr.BeginEdit(); dr["ENAME"] = "JOZSI"; dr.EndEdit(); nikdbDataSet valtozas=(nikdbDataSet)nikdbDataSetVariable. GetChanges(DataRowState.Modified); if (valtozas.HasErrors) { nikdbDataSetVariable.RejectChanges(); } else { nikdbDataSetVariable.AcceptChanges(); eMPTableAdapter.Update(valtozas); } OE-NIK HP
4. 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]; // EZ NEM A LINQ EXTENSION METHOD, CSAK UGYANAZ A NEVE! A kód papíron működik (VS2005-ben még ezt használtam ) … Most teszteltem VS2010 alatt: mintha működne (a 14 soros táblánál 14x működik, 15-ödszörre ahogy kell, kiakad, hogy „dataset is empty”)… Közben meg fizikailag a táblából nem töröl semmit valamiért: a program újraindítása után a táblában megint 14 sor van. OE-NIK HP
5. 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()); } Cél: azon nevekkel feltölteni egy listboxot, akiknek a fizetése >= 3000 OE-NIK HP
6. Megjelenítés GUI-n private void button11_Click(object sender, EventArgs e) { dataGridView1.Columns.Clear(); dataGridView1.Rows.Clear(); dataGridView1.DataSource = null; //dataGridView1.DataSource = nikdbDataSetVariable.EMP; dataGridView1.DataSource = eMPBindingSource; } Mindegy h hogyan állítom be az adatforrást OE-NIK HP
Haladó Programozás Adatbázis-elérési módszerek összehasonlítása Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel SQL server elérése Entity Framework módszerrel OE-NIK HP
Entity Framework (LINQ: to SQL / to Entities) ADO.NET Entity Framework (+LINQ to Entites) Teljes ORM N:M kapcsolatokat is támogat Alternatív adatbázis-dialektusokkal is működik/het (Oracle, MySQL...) Entity osztályok létrehozása: Data sources / Add new data source / Database / Entity Data Model Újabb VS verzióknál: Project / Add New Item / Data / ADO.NET Entity Data Model LINQ to SQL Formailag nagyon hasonló Régebbi módszer, NEM UGYANAZ! Csak közvetlen leképezést, és csak MSSQL dialektust támogat Egyszerű és gyors, de nagyon korlátozottan használható („Rapid development”) Osztályok létrehozása: Project/Add Class/LINQ to SQL classes OE-NIK HP
Entity model megközelítési módok Code First: Először hozzuk létre az osztályokat, és ebből az adatbázist Database/SQL First: Kész adatbázisból csinálunk modell osztályokat Model First: Modellező eszközzel „megrajzoljuk” az adatmodellt (= osztálydiagramot) ( http://msdn.microsoft.com/en-us/magazine/hh148150.aspx ) OE-NIK HP
Entity Framework verziók 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” Teljesen használható ORM! EF5, EF6, EF 6.1 https://msdn.microsoft.com/en-us/data/jj574253.aspx Frissíthető (nekünk nem kell, jó a beépített): > NuGet> Install-Package EntityFramework (esetleg: -Version x.x.x) > Entity Framework 6 Tools for Visual Studio: http://www.microsoft.com/en-us/download/details.aspx?id=40762 OE-NIK HP
LocalDB létrehozása In-Solution In-Profile Project / Add New Item / Service-based Database (ez SQL server file lesz. Local Database: SQL server compact file) Nekünk mindkettő jó, service-based-et használunk: EmpDept Előbb feltöltjük az adatbázist, majd azután generálunk osztályokat In-Profile Server Explorer -> Right click (Data Connections) -> Add Connection ( Microsoft SQL Server + .Net provider for SQL Server <OK>) Server name = (localdb)\v11.0 , Database name = EMPDEPT <OK> "Database does not exist. Attempt to create?" <YES> Akár a „Create New SQL Server Database” is jó, ugyanilyen lépésekkel OE-NIK HP
Adatbázis feltöltése Új DB-re jobbkatt, New query, a létrehozó SQL -ből mindent copypaste, Execute, ez után a query bezárható (Új db /tables- re jobbkatt, refresh: táblák megjelennek) Project, Add new Item, ADO.NET Entity Data Model <ADD>; Generate from database <NEXT>; az MDF file legyen a legördülő menüben + save connection settings <NEXT>; EF6.0 <NEXT>; Mindegyik tábla mellett pipa + Model namespace = EmpDeptModel <FINISH> Konfigurációtól függően: Template can harm your computer, click ok to run ... <OK> <OK> ( http://msdn.microsoft.com/en-us/data/jj206878 ) Eredmény: automatikusan generált osztályok (mint DataSetnél), csak ezek nagyrészt generikus osztályok típusparaméterezett változatai ~30KB a két táblás adatbázis http://users.nik.uni-obuda.hu/hp/SQL_empdept.sql OE-NIK HP
1. Inicializálás 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
2. INSERT var ujdolg = new EMP() { ENAME = "BELA", MGR = null, DEPTNO = 20, EMPNO = 1000 }; ED.EMP.Add(ujdolg); // régen: AddObject ED.SaveChanges(); Console.WriteLine("Insert OK"); OE-NIK HP
3. UPDATE var valaki = ED.EMP.Single(x => x.EMPNO == 1000); valaki.ENAME = "JOZSI"; ED.SaveChanges(); Console.WriteLine("Update OK"); OE-NIK HP
4. DELETE var valaki = ED.EMP.Single(x => x.EMPNO == 1000); ED.EMP.Remove(valaki); // régen: DeleteObject ED.SaveChanges(); Console.WriteLine("Delete OK"); OE-NIK HP
5. SELECT string s = "", sep=""; foreach (var dolg in ED.EMP.Where(dolgozo => dolgozo.SAL >= 3000)) { s += sep + dolg.ENAME; sep = ","; } Console.WriteLine(s); Console.WriteLine( string.Join(";", ED.EMP.Select(x => x.ENAME)) ); Cél: azon nevekkel feltölteni egy listboxot, akiknek a fizetése >= 3000 OE-NIK HP
6. Megjelenítés GUI-n { dataGridView1.Columns.Clear(); dataGridView1.Rows.Clear(); dataGridView1.ItemsSource = null; var dolgozok = from dolgozo in NE.EMP orderby dolgozo.ENAME select dolgozo; dataGridView1.ItemsSource = dolgozok.ToList(); } Így bindelhető DataContexten keresztül is ItemsSource csak dolgozok.ToList() lehet, vagy teljes tábla esetén ED.EMP.Load() után ED.EMP.Local Mindegy h hogyan állítom be az adatforrást OE-NIK HP
+1 JOIN var dolgozok = from dolgozo in NE.EMP join reszleg in NE.DEPT on dolgozo.DEPTNO equals reszleg.DEPTNO select new { dolgozo.ENAME, dolgozo.SAL, reszleg.DNAME }; VAGY Lazy Loading kihasználásával: select new { dolgozo.ENAME,dolgozo.SAL,dolgozo.DEPT.DNAME Mindegy h hogyan állítom be az adatforrást OE-NIK HP
ORM használatának előnyei A kódban sehol sem használunk dialektus függő SQL utasításokat Bármikor dialektust/szervert válthatunk a kód átírása nélkül A string formátumú SQL utasítások helyett a fordítás közben szintaktikailag ellenőrzött lekérdező formátumot használunk A fordítás közben kiderül, ha a bárhol szintaktikai hiba van A string formátumú SQL paraméterek (string összefűzés) helyett változókat használunk lekérdezés paraméterként SQL injection elkerülése A lekérdezések eredménye nem általános anonymous típus / objektum / asszociatív tömb Helyette erősen típusos ismert típusú érték / példány / lista Az ORM rétegre +1 réteg elhelyezésével könnyedén megoldható az adatforrás tetszőleges cseréje és a kód tesztelése Repository Pattern, Dependency Injection Pattern OE-NIK HP
Feladatok Adjunk hozzá a projekthez egy „Service-Based Database” elemet EmpDept.mdf névvel, ezt töltsük föl az orademo.sql –ből, majd hozzunk létre Entity osztályokat! Határozzuk meg részleg nevenként a dolgozók átlagjövedelmét (jövedelem = fizetés+jutalék)! Határozzuk meg a legnagyobb (legtöbb főt foglalkoztató) részleg minden adatát! Melyik a legkisebb összfizetésű munkakör? / Írjuk ki a munkaköröket átlagfizetés szerinti sorrendben. Kik azok a dolgozók, akik az elnök felvétele utáni 30 napon belül lettek felvéve? OE-NIK HP
Táblák Oracle demo táblák OE-NIK HP
Források http://msdn.microsoft.com/en-us/library/bb882674 http://msdn.microsoft.com/en-us/library/ms254937 … és még soksok link az msdn.microsoft.com –ról … és még soksok link a stackoverflow.com –ról LINQ: Reiter István: C# jegyzet (http://devportal.hu/content/CSharpjegyzet.aspx) , 250. oldal (A könyv az alap LINQ to Objects-et tartalmazza) OE-NIK HP
OE-NIK HP
OE-NIK HP