Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
Rétegek (layering) Cél: az implementációs részletek elrejtése, hogy a „felső” réteg ne függjön a nem szomszédos „alsó” rétegektől Hasonló elv: operációs rendszer rétegzett felépítése Az „Alapvető műveletek” listán fogunk mindegyik módszernél végigmenni
Tier vs Layer Layer: logikai felbontása az osztályoknak Az egy rétegbe tartozó osztályok egy közös „magasabb rendű” feladatot szolgálnak ki (pl. megjelenítés, adatkezelés…) Egyértelműen definiált, hogy melyek azok az osztályok, amelyek a rétegen kívülről elérhetőek A külső (szolgáltatott és felhasznált) funkcionalitásokat interfészekkel írjuk le Akkor jól megírt egy alkalmazás, ha egy réteg egy az egyben kicserélhető egy teljesen máshogy implementált, de azonos interfészekkel dolgozó másik komponensre Tier: fizikai felbontása az alkalmazás komponenseinek Szoftver- vagy hardver-komponensek, amik a rétegeket futtatják Nem feltétlenül azonos felbontású, mint a rétegek Az „Alapvető műveletek” listán fogunk mindegyik módszernél végigmenni
Alkalmazás rétegek Mindegyik réteg felbontható belső rétegekre is Kapcsolódási pontok: interfészek segítségével Az „Alapvető műveletek” listán fogunk mindegyik módszernél végigmenni
Onion / Hexagonal architecture „Cross cutting concern”, „Aspect oriented programming”
Cross cutting concerns (Aspects) „Cross cutting concern”, „Aspect oriented programming”
Legalsó réteg: adatbázis/entities Mai nap: a Data Access Layer implementációs lehetőségei Market Share adatok (Gartner, Mar/2012)
Népszerűség szerint (db-engines.com, SEP/2018)
MSSQL 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épek egy részén van MSSQL 2014 Express is, ha esetleg 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)
LocalDB létrehozása In-Solution In-Profile Adatok feltöltése 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 Adatok 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 A táblák minden futtatáskor visszaállnak az eredeti állapotra!
DbConnection vs DataSet vs Entity Framework Cél: adatbázis-kapcsolat felhasználása, SQL utasítások feldolgozása 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 Egyedi megközelítés Entity Framework Az SQL réteg fölé ORM (Object Relational Mapping) réteget helyezünk: a táblákat mint objektumok általános gyűjteményét kezeljük Tervezési mintákat felhasználó, általános megközelítés Az „Alapvető műveletek” listán fogunk mindegyik módszernél végigmenni
Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
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
1. Inicializálás string connStr = @"Data Source=(LocalDB)\v11.0;AttachDbFilename=path\to\empdept.mdf;Integrated Security=True;"; SqlConnection conn; private void Connect() { conn = new SqlConnection(connStr); conn.Open(); Console.WriteLine("CONNECTED"); }
2. INSERT private void Insert() { SqlCommand cmd = new SqlCommand("insert into EMP (ENAME, MGR, DEPTNO, EMPNO) values ('BELA', NULL, 20, 1000)", conn); int affected=cmd.ExecuteNonQuery(); Console.WriteLine(affected.ToString()); }
3. UPDATE private void Update() { SqlCommand cmd = new SqlCommand("update EMP set ENAME='JOZSI' where EMPNO=1000", conn); int affected=cmd.ExecuteNonQuery(); Console.WriteLine(affected.ToString()); }
4. DELETE private void Delete() { SqlCommand cmd = new SqlCommand("delete from EMP where EMPNO=1000", conn); int affected=cmd.ExecuteNonQuery(); Console.WriteLine(affected.ToString()); }
5. SELECT private void Select() { SqlCommand cmd = new SqlCommand("select * from EMP where SAL>=3000 order by ENAME", conn); SqlDataReader reader = cmd.ExecuteReader(); while (reader.Read()) Console.WriteLine(reader["ENAME"].ToString()); } reader.Close(); Cél: azon nevekkel feltölteni egy listboxot, akiknek a fizetése >= 3000
5. SELECT for (int i = 0; i < reader.FieldCount; i++) { string coltext = reader.GetName(i).ToLower(); Console.WriteLine(coltext); } for (int i = 0; i < reader.FieldCount; i++) { Console.WriteLine(reader[i].ToString()); Console.WriteLine(reader.GetValue(i)); Console.WriteLine(reader.GetDecimal(i)); }
Problémák SQL Injection: Figyelni kell rá, hogy a usertől kapott adat SOHA ne értelmeződjön utasításként string uName = "yyy", uPass = "xxx"; string sql = $"SELECT * FROM users WHERE username='{uName}' AND userpass=sha2('{uPass}'); uPass = "x') OR 1=1 OR 1<>sha2('x"; Az üzleti logikai kódba bele kell helyezni az SQL kódot, amit módosítani kell adatbázis szerver vagy adatstruktúra módosítás esetén. Az üzleti logika SOHA ne függjön az adattárolás módjától Megoldás: Prepared statements (sql command parameters) Valamilyen erősen típusos, az SQL funkcionalitásával azonos (vagy ahhoz nagyon közelítő) réteget helyezünk az SQL réteg fölé
Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
ADO.NET: DataAdapter/DataSet/DataTable „Kapcsolat nélküli” adatbázis-elérés (Disconnected mode) 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; egyedi megközelítés 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.
DataSet létrehozása (Visual Studio) Server explorer és Data Sources (Shift+Alt+D) fül kell Server explorer: Adatbázis/connection létrehozása Például LocalDb is jó 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 a tervező nézetben az ablakra egyszerűen ráhúzzuk a táblát, máris kész az alkalmazás Szerkesztőfelület + beszúrás + törlés + grid
1. Inicializálás private void Init() { eMPTableAdapter.Fill(nikdbDataSetVariable.EMP); Console.WriteLine("CONNECTED"); }
2. INSERT private void Insert() { 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); Console.WriteLine("DONE"); }
3. UPDATE private void Update() { 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); }
4. DELETE private void Delete() { 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 )
5. SELECT private void Select() { foreach (DataRow dr in nikdbDataSetVariable.EMP.Select("sal>=3000")) Console.WriteLine(dr["ENAME"].ToString()); } Cél: azon nevekkel feltölteni egy listboxot, akiknek a fizetése >= 3000
Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
A korábbi megközelítések hátránya Nagyon nehéz szétválasztani az üzleti logikát és az adatfeldolgo-zást végző kódot Nagyon nehéz olyan kódot írni, amelyben ugyanaz az üzleti logikai kód használható attól függetlenül, hogy milyen adatforrást használ (az adatforrás lehet List<T>, XML, MySQL Adatbázis, Oracle Adatbázis, MSSQL Adatbázis …) Nagyon nehéz olyan kódot írni, amelyben futásidőben változtatható, hogy az adatokat honnan szedje Nagyon nehéz olyan kódot írni, amelyhez könnyű igazán jó egységteszteket írni (üzleti logika tesztelése ténylegesen működőképes, ténylegesen használt adatelérő réteg nélkül)
LINQ (Language Integrated Queries) Gyűjtemények szintaktikailag egyszerű és forrásfüggetlen kezelését biztosítja Szintaktikailag egyszerű: (ciklusokkal, elágazásokkal megoldható) gyakori feladatok megoldását biztosító „operátorok” Forrásfüggetlen: tömb, lista, XML, adatbázis ugyanolyan módon kezelhető LINQ To Objects, LINQ To XML, LINQ to Entities, ... Részei és támogató technológiák (részletek: C# gyakorlaton) LINQ operátorok LINQ lekérdezések kulcsszavai (from, where, select, join, orderby...) Lambda kifejezések Kiegészítő metódusok var kulcsszó és névtelen osztályok .NET Framework version 3.5-ben jött Forrásfüggetlenségnél az adatbázis után említsd, hogy azért queries, mert a szintaxis eléggé hasonlít a standard SQL szintaxisra. ... = a lánc folytatható, félkövérrel amit ezen az órán veszünk LINQ operátorok = igazából egy csapat függvény LINQ lekérdezések kulcsszavai = where, orderby ... Ezek tartoznak igazából a linq-hoz. A másik három „támogató technológia” A kiegészítő metódusokat (extension methods) nem tanuljuk
LINQ operátorok Ciklusokkal megoldható gyakori feladatok megoldására Elemkiválasztás – első, utolsó, egyetlen, ... Szűrés – tulajdonságnak megfelelő... Rendezés – előrefelé, megfordítás, ... „Halmaz”kezelés – unió, metszet, ... Aggregáció (~számítások) – max, min, ... Csoportosítások IEnumerable<T> interfész új (kiegészítő) metódusai ... LINQ To Objects, LINQ To XML, LINQ to Entities, ... IEnumerable<T>-n dolgoznak, a kimenet többnyire: IEnumerable<T> vagy IEnumerable<X>, emiatt láncolhatók T vagy X Nagyon sokszor metódussal paraméterezhetők T: a típus, amin dolgozom. X: másik (bármilyen) típus, pl Selectből, Min-ből, Max-ból nem ugyanaz a típus jön vissza értelemszerűen! Még egy tulajdonságot tudsz mondani: azt, hogy ELÉG GYAKRAN METÓDUSSAL PARAMÉTEREZHETŐK (pl. lambdák!!!) Ha akarsz, próbáltass ki velük itt pár egyszerű metódust és a láncolást. Utána talán a lambdát is. List<Hallgato> vegzettHallgatok = ... List<Hallgato> aktivHallgatok = ... IEnumerable<Hallgato> osszesHallgato = vegzettHallgatok.Concat(aktivHallgatok); int maxKredit = osszesHallgato.Max(x => x.Kredit); IEnumerable<string> aktivHallgatokNevei = aktivHallgatok.Select(x => x.Nev); IEnumerable<Hallgato> hallgatokAtlagSorrendben = aktivHallgatok.OrderBy(x => x.Atlag); IEnumerable<Hallgato> elsoHuszAtlagSzerint = hallgatokAtlagSorrendben.Reverse().Take(20);
Metódusok hozzáadása ? A meglévő gyűjteményekhez akarunk új funkciókat biztosítani, DE … az interfész definíció módosítása nem kívánt következményekkel jár … interfészhez nem tudunk implementációval rendelkező metódust írni
Kiegészítő metódusok
Lambda kifejezések használata LINQ metódusokkal A lambda kifejezések… A LINQ kiegészítő metódusok paraméterei Automatikusan meghívódik mindegyik gyűjtemény elemre Bemenete IEnumerable<T> esetén tipikusan T Kimenete változó (pl. WhereSzűrésbool; OrderByRendezésIComparable) A lambda kimenetekből határozza meg a LINQ metódus kimenetét, ami lehet IEnumerable<T>, IEnumerable<X>, T, int Adatbázisokkal Azonos szintaxis, IQueryable<T> bővítményei expression lambda optimalizálható!
Kiegészítő metódusokkal… Ugyanazt a LINQ metódust kell meghívni a tipikus feladatokra, függetlenül attól, hogy konkrétan milyen gyűjteményt használunk A gyűjtemény sokszor interfész típusú metódusparaméter vagy konstruktorparaméter is, így az üzleti logika tényleg nem fogja tudni, hogy milyen adaton kell pontosan dolgoznia (DEPENDENCY INJECTION, részletezve későbbi előadásokon) A meghívott fix metódus az interfészhez deklarált extension method, ami a műveletet (szűrés/sorbarakás/stb) elvégzi, bármilyen gyűjtemény is a kapott referencia List<T>, XML file C# gyakorlat, második hét Adatbázis C# gyakorlat, harmadik hét … … XML formátum?
XML (w3schools.com) Hierarchikus adatleíró formátum <?xml version="1.0"?> <bookstore> <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> <book category="WEB"> <title lang="en">Learning XML</title> <author>Erik T. Ray</author> <year>2003</year> <price>39.95</price> </bookstore> XAML elmagyarázása előtt tudni kell, mi az az XML… Hierarchikus adatleíró formátum XML deklarációk + elemek + attribútumok Elemek: <bookstore></bookstore>... = <tag></tag> Attribútumok: <book>-ban category=„…” …
XML Felépítését szigorú szabályok korlátozzák Mindegyik elemnek lehet: Első sor: opcionális formátumspecifikáció, kiegészíthető karakterkódolással: <?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="UTF-8"?> Mindegyik elemnek lehet: Szöveges tartalma Alelemei Attribútumai, amelyek az adott elemhez adnak meg tulajdonságokat Kötelezően kell lennie egy gyökérelemnek, ami az egész dokumentumot közrefogja (<bookstore> elem) Minden elem lezárása kötelező (<tag></tag> vagy <tag />) Az egymásba ágyazás lezárásainak megfelelő sorrendben kell történniük Rosszul formázott: <a><b></a></b> Jól formázott: <a><b></b></a> A kis- és nagybetűk különbözőek Ezt igazából nem most akarjuk leadni.
XML <book category="COOKING"> <title lang="en">Everyday Italian</title> <author>Giada De Laurentiis</author> <year>2005</year> <price>30.00</price> </book> Egy objektum leírását a beágyazott elemek és attribútumok szolgáltatják Ugyanígy (a beágyazással) hierarchia, tartalmazás is reprezentálható! – XML értelmezésétől függ <?xml version="1.0"?> <bookstore> <book category="COOKING"> ... </book> <book category="WEB"> ... </book> </bookstore>
XML + .NET Háromféle XML-technológia XmlReader, XmlWriter Gyorsak, kevés memóriát fogyasztanak Csak előrefelé tudnak dolgozni Bonyolult az összetett xml-ek megírása Az xml-transzformáció borzasztó tud lenni (node csere, node változtatás, etc) XmlDocument, XmlNode, XmlElement, Xml*... Lassú, sokat fogyaszt (a memóriában felépíti a teljes dokumentum fáját) Ezzel sem feltétlenül egyszerűek az algoritmusok Előnyös, ha transzformálni akarunk XDocument, XElement, XAttribute, XDeclaration, X*... LINQ!
Web programozás és haladó fejlesztési technikák Adatbázis-elérési rétegek Adatbázisok elérése DbConnection/DbReader módszerrel SQL server elérése DataSet módszerrel Adatfüggetlen logika: LINQ, XML formátum SQL server elérése Entity Framework módszerrel (ORM + DB-LINQ)
ORM = Object Relational Mapping – alapfeladat REJTETT fizikai adatelérés, ami SQL utasításokkal dolgozik Kívülről használható műveletek: dialektus-függetlenség Dialektus-független konverzió: a műveletek végrehajtása független legyen attól, hogy milyen a használt SQL dialektus / adattárolási mód A felső réteg ne SQL nyelvet lásson: Lambda kifejezések (Java Stream Api/C# LINQ) vagy saját lekérdező nyelv (Doctrine) vagy egyszerű CRUD metódusok (Active Record rendszerek) Objektum-tár A felső réteg csak típusos objektumokat lát A lekérdezés eredmények objektumokká/gyűjteményekké konvertálódnak Akár műveletek között is megoszthatóak Az ORM segítségével a felsőbb réteg képes az adatbázist memóriában lévő objektumgyűjteményként kezelni, függetlenül a ténylegesen használt fizikai tárolási módtól
ORM = Object Relational Mapping – rendszerek C#: Entity Framework Java: Hibernate/JPA Python: Django ORM, SQLAlchemy Ruby on Rails PHP: Eloquent, Propel, Doctrine
Doctrine DQL
Java + Hibernate + Stream API
C# + Entity Framework + LINQ Részletesebben: C# gyakorlatok a mostani héten (LINQ to XML) és a következő héten (Linq to Entities)
EF Rétegek
Entity Framework (LINQ: to SQL / to Entities) 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 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
Entity Framework verziók https://docs.microsoft.com/en-us/ef/ef6/what-is-new/past-releases EF1 = EF3.5 .NET 3.5 (2008) EF4 .NET 4 (2010) „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” (2011) a furcsa ObjectContext api helyére a logikus DbContext api került! EF4.3 „Code First Migrations” (2012) használható ORM! EF5 (2012), API változások … EF6 (2013), API változások … EF 6.1.2 (2014), EF 6.2 (2017) elterjedt és JÓ ORM!
Entity Framework Core EF7: RC1 2015 … „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. EF6.x may still be the most suitable release for many applications” EF7 átnevezve, majd kiadva: EF Core „Because of the fundamental changes in EF Core we do not recommend attempting to move an EF6.x application to EF Core unless you have a compelling reason to make the change. You should view the move from EF6.x to EF Core as a port rather than an upgrade.„
Entity Framework Core EF Core 1.0: 2016. 06. 27. (with ASP.NET Core 1.0) EF Core 2.0: 2017. 08. 14. (with ASP.NET Core 2.0) EF Core 2.1: 2018. 05. 30. (with ASP.NET Core 2.1) LAZY LOAD + GROUP BY, elértünk az EF 6.1 szintjére… EF Core 2.2: év vége, „small release” https://docs.microsoft.com/en-us/ef/efcore-and-ef6/features - Jó: Client-side/query keys, Cmdline, Mixed client/server evaluation, Raw SQL with LINQ, Statement batches, DbContext pooling - Nem gond: no graphical visualization, no EDMX, Entityless many-to-many - Kis gond: Limited inheritance models, No entity splitting, No stored procedures, No Database.Log - NAGYON NAGY gond: No change tracking via Proxies, No lifecycle hooks, No update model from database
Entity model megközelítési módok Code First: Kézzel megírjuk a POCO entity osztályokat és a DbContext osztályt, és ebből generáljuk az adatbázist Database/SQL First: Kész adatbázisból generáljuk le modell és a context osztályokat Model First: Modellező eszközzel „megrajzoljuk” az adatmodellt (= osztálydiagramot) (EF 6-ban utoljára, a későbbi verziókkal nem támogatott) ( http://msdn.microsoft.com/en-us/magazine/hh148150.aspx )
A modell legenerálása (SQL first) Előfeltétel: meglévő táblák http://msdn.microsoft.com/en-us/data/jj206878 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> Eredmény: automatikusan generált osztályok (mint DataSetnél), csak ezek nagyrészt generikus osztályok típusparaméterezett változatai vagy POCO osztályok ~30KB a két táblás adatbázis http://users.nik.uni-obuda.hu/hp/SQL_empdept.sql
1. Inicializálás ED = new EmpDeptEntities(); Console.WriteLine("Connect OK"); // DbSet<T> típus, LINQ bővítménymetódusokkal // LINQ query syntax is lehetséges // IEnumerable<T> vs IQueryable<T> DEPT reszleg = ED.DEPT.First(); Console.WriteLine(reszleg.DNAME); // Lazy loading string reszlegNeve = ED.EMP.First().DEPT.DNAME;
2. INSERT EMP ujdolg = new EMP() { ENAME = "BELA", MGR = null, DEPTNO = 20, EMPNO = 1000 }; ED.EMP.Add(ujdolg); ED.SaveChanges(); // Save via change tracking! Console.WriteLine("Insert OK");
3. UPDATE EMP valaki = ED.EMP.Single(x => x.EMPNO == 1000); valaki.ENAME = "JOZSI"; ED.SaveChanges(); Console.WriteLine("Update OK");
4. DELETE EMP valaki = ED.EMP.Single(x => x.EMPNO == 1000); ED.EMP.Remove(valaki); ED.SaveChanges(); Console.WriteLine("Delete OK");
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 Saját EF/Linq provider írásával akár tetszőleges tárolási mód is lehetséges 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
ORM használatának hátrányai “ORM is a terrible anti-pattern that violates all principles of object-oriented programming, tearing objects apart and turning them into dumb and passive data bags. There is no excuse for ORM existence in any application” http://www.yegor256.com/2014/12/01/orm-offensive-anti-pattern.html Ez persze csak egyetlen vélemény, de tipikus negatívumok: Nehezebb konfiguráció Nagyobb memóriaigény Nagyobb CPU igény Bonyolultabb lekérdezések szegényes/nehéz támogatása Nehéz optimalizáció
ORM sebessége (C#)
ORM sebessége (PHP)
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)