Language Integrated Query, LINQ, och databaser 1
Imperativ eller deklarativ programmering Imperativ programmering Du som programmerare beskriver i detalj alla steg som måste utföras för att lösa en viss uppgift Det är vad du har gjort fram till nu i C# Deklarativ programmering Du som programmerare deklarerar enbart villkoren för att en viss uppgift ska utföras Det gör du mot databaser när du använder SQL Det är det du gör i ett.net baserat språk när du använder LINQ 2
Ett enkelt exempel med LINQ using System; using System.Linq; public class Person public string Namn get; private set; public int Ålder get; private set; public Person(string namn, int ålder) Namn = namn; Ålder = ålder; public override string ToString() return Namn + ", " + Ålder + " år"; Till det här omvandlar kompilatorn LINQ uttrycket var ungdomar = medlemmar.where(individ => individ.ålder < 20).OrderBy(individ => individ.namn).select(individ => individ); public static class Program public static void Main() Person[] medlemmar = new Person("Kalle", 43), new Person("Lisa", 64), new Person("Nisse", 12), new Person("Erik", 13), new Person("Kajsa", 42), new Person("Klara", 32) ; var ungdomar = from individ in medlemmar where individ.ålder < 20 orderby individ.namn select individ; foreach (Person junior in ungdomar) Console.WriteLine(junior); Erik, 13 år Nisse, 12 år 3
Syntax, LINQ Returtypen är egentligen för det mesta IEnumerable<någon typ > from, beskriver datakällan Lika betydelse som i SQL OBS! select kommer sist! var ungdomar = from individ in medlemmar where individ.ålder < 20 orderby individ.namn select individ; Liknande operationer som i SQL är möjliga, till exempel group och join. Datakällor kan vara arrayer, collection-klasser, XML, databas-tabeller, med mera. Läs om LINQ i, https://msdn.microsoft.com/en-us/library/bb397933.aspx 4
Exekvering av ett LINQ-uttryck I LINQ är exekveringen av en fråga skild från definitionen av själva frågan. Frågan exekveras först när den efterfrågade informationen behövs! Till exempel när informationen listas upp i en efterföljande foreach-loop. 5
Olika typer databaser För att databaser ska gå att använda i Visual Studio Community 2017, måste ett av eller båda av följande tillägg installeras som Workloads, via meny-alternativet Tools-> Get Tools and Features... ASP.NET and web development Data storage development Observera att detta är redan gjort på de datorer som finns i datorsalarna Databasfiler Microsoft Access databasfiler,.accdb,.mdb Microsoft SQL Server databasfiler,.mdf Microsoft SQL Server Compact filer,.sdf Inte helt enkla att koppla mot LINQ, använd.mdf filer i stället Servers Microsoft SQL Server Oracle Database server anslutningar, förutsätter att anslutnings-komponenter, ODAC, laddas ner från Oracle och installeras Andra, förutsätter att anslutnings-komponenter, laddas ner från databasleverantören och installeras Tools and Features 6
Ansluta till en databas-fil Databasfiler En redan existerande databasfil kopieras in till Visual Studio-projektet genom att välja i menyn Project välja; Add Existing Item, som filtyp välj Data files En ny databasfil skapas i ett Visual Studio-projekt genom att välja; Add New Item, Service-based Database, skapar en SQL Server fil av typen *.mdf För att ansluta till databasfilen, dubbelklicka på den. Den bör komma upp i Server Explorer. Om den inte gör det, prova följande: Anslut i Server Explorer med Data source: Microsoft SQL Server Database File, för att få en lokal databas i applikationen som inte kräver någon Databasserver Om du får ett rött kryss på ikonen för databasen i Server Explorer, prova att högerklicka på ikonen och välj refresh 7
Ansluta till en databas-server Servers Visual Studio har en egen databasserver Det är även möjligt att installera en separat SQL Server Express, läs i så fall följande handledning https://docs.microsoft.com/en-us/sql/relationaldatabases/tutorial-getting-started-with-the-database-engine En varning! Det är inte helt enkelt att installera servern på en separat maskin och få den tillgänglig på klient-datorer Ansluta den databasserver som Visual Studio 2017 har Data source: Microsoft SQL Server (SqlClient) Server name: (localdb)\mssqllocaldb Select or enter a database name: Här ska du skriva in namnet på den databas som du vill arbeta med Klicka på OK Ta bort en databas som finns på Visual Studios server I Server Explorer högerklicka på databasanslutningen och välj Browse in SQL Server Explorer I SQL Server Explorer högerklicka på databasen och välj Delete Om servern inte kan ta bort databasen, prova att stänga alla fönster i vilket databasen hanteras och kryssa i rutan Close existing connections. Prova därefter igen att ta bort databasen. 8
LINQ och SQL Skapa ett vanligt projekt för ett C#-program i Visual Studio I Solution Explorer lägg till en ny databasfil i form av en Service-based Database. För att använda LINQ mot den anslutna databasen måste en databasomgivning, i form av klasser som representerar databasens tabeller finnas. Sådana klasser får du genom att lägga till komponenten ADO.NET Entity Data Model i projektet. För att skapa en Entity Data Model: Välj, Add New Item, Data, ADO.NET Entity Data Model, döp den till lika namn som databasen. Om inte ett klass-diagram med klasser som mappar databasens tabeller öppnades, dubbelkicka på filen namn.edmx i Solution Explorer Klasserna finns i den namnrymd som har samma namn som projektet i Visual Studio Klasserna är deklarerade som partial, det innebär att du kan lägga till innehåll genom att skapa en egen motsvarande partial-deklarerad del till en eller flera av klasserna. 9
En utsökning using System; using System.Linq; namespace EnUtsökning class Program public static void Main() using (AnkeborgEntities db = new AnkeborgEntities()) var utsöktapersoner = from person in db.person where person.ålder >= 30 && person.ålder < 40 select person; Jan Lånben, 35 Musse Pigg, 37 Klara Kluck, 32 foreach(person utsökt in utsöktapersoner) Console.WriteLine(utsökt.Namn + ", " + utsökt.ålder); Console.ReadKey(); 10
LINQ och lokala databasfiler För att använda LINQ tillsammans med Microsoft SQL Server databasfiler,.mdf, i ett Visual Studio projekt gör så här: 1. Skapa en databasfil via projektets, Add New/Existing Item, välj Service-based Database och ge filen ett lämpligt namn. 2. Lägg in de tabeller som behövs via Server Explorer. Den hittar du i Visual Studio, meny VIEW. 3. Skapa en databasomgivning, via projektets Add New Item, Data, välj ADO.NET Entity Data Model 4. Formulera dina frågor mot databasen med hjälp av LINQ 11
Exempel; Min bokhylla public static void Main() BokDBEntities databasen = new BokDBEntities(); Console.WriteLine("SKRIVER UT DATABASENS ALLA BÖCKER"); SkrivBöcker(databasen); Console.WriteLine("SÄTTER IN EN NY BOK I DATABASEN"); Bok nybok = new Bok() Titel = "Fel mat", Författare = "Zeke Varg", Pris = 47m ; SättInBok(databasen, nybok); SkrivBöcker(databasen); Console.WriteLine("ÄNDRAR ZEKE VARGS BÖCKER TILL ANDRA VERSIONEN"); UppdateraBok(databasen); SkrivBöcker(databasen); Console.WriteLine("TAR BORT ALLA ZEKE VARGS BöCKER"); RaderaBok(databasen); SkrivBöcker(databasen); Console.WriteLine("\nTryck på Enter för att avsluta."); Console.ReadLine(); 12
Exempel; En select-sats private static void SkrivBöcker(BokDBEntities databasen) var resultat = from bok in databasen.bok select bok; foreach (var rad in resultat) Console.WriteLine("0, 1, pris: 2:c", rad.författare, rad.titel, rad.pris); Console.WriteLine(); 13
Exempel; Insättning private static void SättInBok(BokDBEntities databasen, Bok nybok) databasen.bok.add(nybok); databasen.savechanges(); 14
Exempel; Ändra private static void UppdateraBok(BokDBEntities databasen) var urval = from bok in databasen.bok where bok.författare == "Zeke Varg" select bok; foreach (Bok utvaldbok in urval) utvaldbok.titel += ", version 2"; databasen.savechanges(); 15
Exempel; Ta bort private static void RaderaBok(BokDBEntities databasen) var skabort = from bok in databasen.bok where bok.författare == "Zeke Varg" select bok; foreach (Bok bok in skabort) databasen.bok.remove(bok); databasen.savechanges(); 16
Ett exempel, databasdemo I anslutning till automatiskt genererade filen Telefonlistan.edmx finns klassen, Person, en klass som representerar en rad tabellen Person, med följande PersonID, en property som motsvarar PersonID i en rad i tabellen Person Name, en property som motsvarar Name en rad i tabell Person Phone, en property som motsvarar Phone i en rad i tabell Person Filen PersonEdit.cs, innehåller mina tillägg till klassen Person 17
databasdemo private void Form1_Load(object sender, EventArgs e) db = new TelefonlistanEntities(); Uppdatera(); private void Uppdatera() var personerna = from person in db.person select person; listboxpersoner.items.clear(); listboxpersoner.items.addrange(personerna.toarray()); private void ButtonLäggTill_Click(object sender, EventArgs e) Person nyperson = new Person(); nyperson.name = textboxnamn.text; nyperson.phone = textboxnummer.text; db.person.add(nyperson); db.savechanges(); Uppdatera(); Det är praktiskt att samla alla uppdateringar av vad ett fönster ska visa till en enda metod. Då kan den metoden anropas så snart som bakomliggande data har förändrats. 18
LINQ och XML using System; using System.Linq; using System.Xml.Linq; namespace LINQ_XML public class Program public static void Main() Det här är början på ett exempel i vilket LINQ används tillsammans med ett XML dokument. I exempel finns det metoder som visar hur man kan arbeta mot XMLdokumentet Person[] people = new Person[] new Person ID = 1, Name = "Joe", Age = 35, Job = "Manager", new Person ID = 2, Name = "Jason", Age = 18, Job = "Software Engineer", new Person ID = 3, Name = "Lisa", Age = 53, Job = "Bakery Owner", new Person ID = 4, Name = "Mary", Age = 90, Job = "Nurse", ; XDocument xmldokumentet = skapaxmldokument(people); skrivutpersoner(xmldokumentet); // Skriver ut till fil xmldokumentet.save("people.xml"); //Läser in det igen från filen xmldokumentet = XDocument.Load("People.xml"); Ett nog så enkelt alternativ till den här är lösningen är samla objekten någon typ collection och arbeta mot den med LINQ. När man behöver spara sin collection till en fil eller läsa in den från fil gör man det med en hjälp av en instans av XmlSerializer Person kalle = new Person ID = 5, Name = "Carl", Age = 24, Job = "Banker" ; läggtillenperson(kalle, xmldokumentet); skrivutpersoner(xmldokumentet); 19
LINQ, skapa ett XML-dokument private static XDocument skapaxmldokument(person[] people) XDocument dokumentet = new XDocument( new XDeclaration("1.0", "utf-8", "yes"), new XComment("Idén hämtad från http://www.dreamincode.net/forums/topic/218979-linq-to-xml/"), new XElement("People", from person in people select new XElement("Person", new XAttribute("ID", person.id), new XElement("Name", person.name), new XElement("Age", person.age), new XElement("Job", person.job)) ) ); return dokumentet; 20
LINQ och XML, hämta objekt från XML private static void skrivutpersoner(xdocument dokument) var personer = from item in dokument.descendants("person") select new Person() ID = int.parse(item.attribute("id").value), Name = item.element("name").value, Age = int.parse(item.element("age").value), Job = item.element("job").value ; foreach (Person person in personer) Console.WriteLine(person); Console.WriteLine(); Flera idéer på hur man med hjälp av LINQ kan använda ett XML-dokument finns i programmet LINQ_XML. Programmet finns i ExempelLINQ.zip 21