1 / 37

Pove z ivanje podataka sa kontrolama na formi - Data Binding sa DLINQ -om

Pove z ivanje podataka sa kontrolama na formi - Data Binding sa DLINQ -om. DLINQ omogućava lakše i elegantnije izvršavanje SQL upita u bazi podataka, nego korišćenjem klasa iz ADO.NET biblioteke

zea
Download Presentation

Pove z ivanje podataka sa kontrolama na formi - Data Binding sa DLINQ -om

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Povezivanjepodataka sa kontrolama na formi - Data Binding sa DLINQ-om • DLINQ omogućava lakše i elegantnije izvršavanje SQL upita u bazi podataka, nego korišćenjem klasa iz ADO.NET biblioteke • DLINQ se nalazi iznad ADO.NET-a i koristi ga, tako da se može reći da DLINQ predstavlja jednu vrstu API-a za korišćenje ADO.NET-a • DLINQ ublažava razliku između SQL-a i objektne paradigme koja se koristi u C#-u i time čini blaži prelaz između razlike rada sa podacima u relacionoj bazi i objektnog koda programa • VS 2008 ima alat za podršku i automatizaciju rada sa DLINQ-om, Object Relational Designer

  2. Object Relational Designer • Object Relational Designer – ORL, omogućava automatsko povezivanje sa bazom podataka i kreiranje čitave infrastrukture klasa koje su potrebne za korišćenje DLINQ-a • ORL se ubacuje u WPF projekat iz menu-a Project / Add New Item... / Data / LINQ to SQL Classes, i zada se novo odgovarajuće ime • ORL automatski kreira novu klasu koja nasleđuje od DataContext klase i čije ime se automatski formira sa prefiksom zadatog imena ORL i sufiksom DataContext • Ako se ORL nazove Northwind, onda je ime nove klase NorthwindDataContext

  3. Object Relational Designer • Da bi ORL mogao da automatski kreira entity klase koje odgovaraju tabelama baze podataka, neophodno je povezati odgovarajuću bazu podataka iz VS2008 • Povezivanje VS i baze podataka se vrši iz prozora Server Explorer (SE) • U gornjem delu prozora SE se nalazi ikona Data Connection koja se selektuje i iz menu-a Tools / Connect to Database... se dobija dijalog box za podešavanje konekcije sa bazom podataka • Za konekciju sa bazom je potrebno da postoji baza podataka kao file tipa *.mdf koji može biti već povezan sa SQL Express serverom – levi deo sledeceg slide-a ili ga tek treba povezati – Attach a data base file – desni deo sledeceg slide-a

  4. Object Relational Designer • Kada se poveže baza podataka sa VS, onda mogu da se uvezu tabele iz povezane baze podataka za koje će ORL automatski da kreira odgovarajuće entity klase • Ispod ikone Data Connection u VS se nalazi ikona nove baze podataka koja je povezana, a ispod koje se nalazi kolekcija Tabels baze podataka • Otvaranjem ove kolecije – klik na + sa leve strane, dobija se spisak svih tabela u povezanoj bazi • Sa desne strane se odabere prozor ORL – Northwind.dbml i jednostavno se prevuku željene tabele u prozor ORL

  5. Object Relational Designer • Za svaku prevučenu tabelu u prozor ORL se automatski kreira odgovarajuća entity klasa čiji je naziv jednak nazivu odgovarajuće tabele • U prevučenim tabelama se mogu brisati polja koja nisu potrebna i koja se neće koristiti u radu sa tabelama baze podataka • Osim navedenih tabela, ORL automatski kreira i konfiguracioni file app.config koji se dodaje projektu • File app.config je xml dokument koji sadrži connection string koji definiše konekciju sa bazom podataka i omogućava da se promene detalji konekcije bez izmene u kodu aplikacije • Od app.config se kreira file application.exe.configgde je application naziv aplikacije i distribuira se zajedno sa application.exe u istom folder-u

  6. app.config xml file <?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> </configSections> <connectionStrings> <add name="Suppliers.Properties.Settings.NorthwindConnectionString" connectionString="Data Source=.\SQLExpress;Initial Catalog=Northwind;Integrated Security=True“providerName="System.Data.SqlClient" /> </connectionStrings> </configuration> • File pod nazivom application.exe.configima potpuno isti sadržaj kao i gore prikazani sadržaj file-a app.config, koji treba da se nalazi u istom folderu kao i prevedeni application.exe file. • Parametri konekcije se mogu promeniti u xml application.exe.configfile-u bez izmene application.exe

  7. Izgled prozora aplikacije

  8. Selekcija dobavljača - suppliers

  9. Definisanje izgleda stavki u combo box-u za dobavljače - suppliers <Window x:Class=”WpfApplication1.Window1” ...> <Window.Resources> <DataTemplate x:Key=”SuppliersTemplate”> <StackPanel Orientation=”Horizontal”> <TextBlock Text=”{Binding Path=SupplierID}” /> <TextBlock Text=” : “ /> <TextBlock Text=”{Binding Path=CompanyName}” /> <TextBlock Text=” : “ /> <TextBlock Text=”{Binding Path=ContactName}” /> </StackPanel> </DataTemplate> </Window.Resources> <Grid> ... </Grid> </Window> <ComboBox ... Name=”suppliersList” IsSynchronizedWithCurrentItem=”True” ItemsSource=”{Binding}” ItemTemplate=”{StaticResource SuppliersTemplate}” />

  10. Definisanje izgleda stavki u list box-u za proizvode - products <ListView ... Name=”productsList” ...> <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Width=”75” Header=”Product ID” DisplayMemberBinding=”{Binding Path=ProductID}” /> <GridViewColumn Width=”225” Header=”Name” DisplayMemberBinding=”{Binding Path=ProductName}” /> <GridViewColumn Width=”135” Header=”Quantity Per Unit”DisplayMemberBinding=”{Binding Path=QuantityPerUnit}” /> <GridViewColumn Width=”75” Header =”Unit Price” DisplayMemberBinding=”{Binding Path=UnitPrice}” /> </GridView.Columns> </GridView> </ListView.View> </ListView>

  11. Klasa za konverziju vrednosti [ValueConversion(typeof(string), typeof(decimal?))] class PriceConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value != null) return String.Format(“{0:C}”, value); else return “”; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } • Klasa za konverziju PriceConverter iz tipa decimal? koji je nullable u entity klasi – može da fali, u tip String u kontroli ListView na formi

  12. Objekat klase PriceConverter kao resurs <Window x:Class=”Suppliers.SupplierInfo” ... xmlns:app=”clr-namespace:Suppliers” ...> <Window.Resources> <app:PriceConverter x:Key=”priceConverter” /> ... </Window.Resources> ... </Window> <GridViewColumn ... Header =”Unit Price” DisplayMemberBinding= “{Binding Path=UnitPrice, Converter={StaticResource priceConverter}}” /> • U XAML kodu se sa: • <app:PriceConverter x:Key=”priceConverter” /> • Kreira objekat priceConverter klase PriceConverter kao resurs koji se koristi u GridViewColumn

  13. Dinamičko povezivanje kontrole ComboBox sa entity klasom <Window x:Class=”Suppliers.SupplierInfo” ... Title=”Supplier Information” ... Loaded=”Window_Loaded”> ... </Window> public partial class SupplierInfo : Window { private NorthwindDataContext ndc = null; private Supplier supplier = null; private BindingList<Product> productsInfo = null; ... } private void Window_Loaded(object sender, RoutedEventArgs e) { ndc = new NorthwindDataContext(); this.suppliersList.DataContext = ndc.Suppliers; }

  14. Dinamičko povezivanje kontrole ComboBox sa entity klasom private void suppliersList_SelectionChanged(object sender, SelectionChangedEventArgs e) { supplier = this.suppliersList.SelectedItem as Supplier; IList list = ((IListSource)supplier.Products).GetList(); productsInfo = list as BindingList<Product>; this.productsList.DataContext = productsInfo; } • EntitySet<Product> klasaimplementiraIListSource interface, koji deklariše GetList metod za kopiranje podataka iz entity set-au IList objekat list • BindingList implementira interface-e koji deklarišu događaje INotifyPropertyChangingiINotifyPropertyChangedna koje reaguju povezane kontrole i vrednosti koje pokazuju se update-uju - ažuriraju

  15. Ažuriranje podataka sa DLINQ-om • Do sada kreirana aplikacija omogućava povezani prikaz podataka o proizvođačima - ComboBox i proizvodima – ListBox • Odnos je M : 1 – jedan proizvođač više proizvoda, i jedan proizvod jedan proizvođač • Promena – ažuriranje podataka nije moguća • Podaci iz baze su povezani sa kontrolama koje ih prikazuju preko Table kolekcija • Promena podataka u kontrolama menja podatke u povezanim entity klasama – u memoriji, ali ne menja podatke u bazi

  16. Ažuriranje podataka sa DLINQ-om NorthwindDataContext ndc = new NorthwindDataContext(); Product product = ndc.Products.Single(p => p.ProductID == 14); product.ProductName = “Bean Curd”; ndc.SubmitChanges(); ndc.Refresh(RefreshMode.OverwriteCurrentValues, ndc.Products); • Podaci u bazi se menjaju preko SQL ili DLINQ upita • Metod SubmitChanges klase ContextData upisuje promene u bazu • Metod Refresh vraća podatke iz baze u Table kolekcije, tj. tako se mogu poništiti promene u kolekciji koje još nisu upisane u bazu • Metod Refresh može da prihvati više kolekcija – parameters kao drugi parametar

  17. Ažuriranje podataka sa DLINQ-om • Metod SubmitChanges klase ContextData upisuje sve promene u bazu • Ako neka promena dovede do greške upisa u bazu, sve se vraća na prethodno stanje, tj. vrši se transakcija i ako bilo koja od operacija izmene ne uspe, sve se vraća na prethodno stanje – roll back • Pri tome se podaci u kolekcijama entity klasa ne menjaju • Pre ponovnog pokušaja ažuriranja treba promeniti podatke koji su doveli do neuspeha • Ako sve izmene u bazi uspeju, transakcija se izvršava – commit, i promene se upisuju u bazu

  18. Konflikti pri ažuriranju podataka • Pri ažuriranju podataka može doći do međusobnog konflikta promena istih podataka koje unose dva korisnika • Ako dva korisnika menjaju iste podatke u bazi onda može da dođe do izgubljenih podataka koje je uneo jedan od korisnika • Metod SubmitChanges može da otkrije kada se to desi i da aktivira ChangeConflictException • SvojstvoChangeConflicts objekta klase DataContextje kolekcija objekata tipa ObjectChangeConflict • SvojstvoIsDeletedje boolean i ukazuje da li drugi korisnik pokušava da briše podatke koji se menjaju

  19. Konflikti pri ažuriranju podataka • Zatim svojstvo MemberConflictskoje je kolekcija objekata tipa MemberChangeConflict koji sadrže korespodentnu vrednost podatka u memoriji, tekuću vrednost podatka u bazi kao i prvobitnu vrednost podatka u bazi koja je učitana • Na osnovu toga se može kreirati procedura razrešenja konflikta – koja od te tri vrednosti će se prihvatiti • Moguće je i da korisnik aplikacije odluči šta da se radi u cilju rezolucije konflikta • KlasaObjectChangeConflict sadrži method Resolve

  20. Method Resolve klaseObjectChangeConflict • Method Resolveima argument tipa enumeracije RefreshModečije vrednosti ukazuju na način rezolucije konflikta • RefreshMode.KeepCurrentValues – tekuće vrednosti u memoriji prepisuju konfliktne vrednosti – tekući korisnik je pobednik konflikta • RefreshMode.OverwriteCurrentValue – tekuće vrednosti iz memorije se prepisuju vrednostima iz baze – tekući korisnik je gubitnik konflikta • RefreshMode.KeepChanges – izmenjene vrednosti od oba korisnika se merdžuju, ako su u različitim kolonama – oba korisnika su pobednici konflikta

  21. Primer rezolucije konflikta try { ndc.SubmitChanges(); } catch (ChangeConflictException) { foreach (ObjectChangeConflict conflict in ndc.ChangeConflicts) { Foreach (MemberChangeConflict changeConflict in conflict.MemberConflicts) { Console.WriteLine(“Conflict Details”); Console.WriteLine(“Original value retrieved from database: {0}”, changeConflict.OriginalValue.ToString()); Console.WriteLine(“Current value in database: {0}”, changeConflict.DatabaseValue.ToString()); Console.WriteLine(“Current value in memory: {0}”, changeConflict.CurrentValue.ToString()); } conflict.Resolve(RefreshMode.OverwriteCurrentValues); } }

  22. Method Resolve klaseObjectChangeConflict • Kolekcija ChangeConflicts klaseDataContext sadrži ResolveAll metod koji omogućava da se ista RefreshMode vrednost primeni za rezoluciju svih konflikata • Ako se metod • ndc.SubmitChanges(ConflictMode.ContinueOnConflict); • Pozove sa ConflictMode.ContinueOnConflict vrednošću enumeracije, onda se prvo probaju sve izmene nakon čega se aktivira ChangeConflictException ako ima jedan ili više konflikata • Ako se metod SubmitChanges zove bez tog argumenta, onda se generiše ChangeConflictException pri svakom konfliktu • Podrazumevano ponašanje je sa vrednošću kolekcije ConflictMode.FailOnFirstConfl ict.

  23. Dodavanje i brisanje podataka NorthwindDataContext ndc = new NorthwindDataContext(...); Table<Product> products = ndc.Products; Product newProduct = new Product() {ProductName = “New Product”, ... }; products.Add(newProduct); ... ndc.SubmitChanges): • Posle poziva metoda SubmitChanges, DataContext objekat će generisatiSQL INSERT naredbu za svaku novu stavku u Table kolekciji Product product = products.Single(p => p.ProductID == 14); products.Remove(product); ... ndc.SubmitChanges): • Posle poziva metoda SubmitChanges, DataContextobjekat će generisati SQL DELETEnaredbu za svaku izbrisanu stavku u Table kolekciji

  24. Ažuriranje proizvoda private void productsList_KeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.Enter: editProduct(this.productsList.SelectedItem as Product); break; case Key.Insert: addNewProduct(); break; case Key.Delete: deleteProduct(this.productsList.SelectedItem as Product); break; } } • Metod productsList ispituje pritisnutu tipku tastature kada se selektuje stavka liste productsList preko svojstva Key objekta e klase KeyEventArgs koja sadrži vrednosti enumeracije System.Windows.Input.Key na osnovu čega se poziva odgovarajući metod za ažuriranje

  25. deleteProduct method private void deleteProduct(Product prod) { MessageBoxResult response = MessageBox.Show(“Delete “ + prod.ProductName, “Confirm”, MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No); if (response == MessageBoxResult.Yes) { supplier.Products.Remove(prod); productsInfo.Remove(prod); this.saveChanges.IsEnabled = true; } } • supplier je objekat entity klase koja služi za povezivanje sa tabelom, Products je kolekcija entity objekata za datog supplier-a – dobavljača • productsInfo je BindingList koja služi za povezivanje sa ListView kontrolom productsList

  26. Izmena i dodavanje proizvoda • Za izmenu i dodavanje proizvoda potrebno je kreirati novu pomoćnu formu sa poljima proizvoda koja se dodaju / menjaju

  27. Izgled forme za editovanje proizvoda

  28. <Window x:Class="Suppliers.ProductForm" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ProductForm" Height="225" Width="515" ResizeMode="NoResize"> <Grid> <Label Height="23" Margin="17,20,0,0" Name="label1" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120">Product Name</Label> <Label Margin="17,60,0,0" Name="label2" Height="23" VerticalAlignment="Top" Width="120" HorizontalAlignment="Left">Quantity Per Unit</Label> <Label Margin="17,100,0,0" Name="label3" Height="23" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120">Unit Price</Label> <TextBox Height="21" Margin="130,24,0,0" Name="productName" VerticalAlignment="Top" Width="340" HorizontalAlignment="Left" /> <TextBox Height="21" Margin="130,64,0,0" Name="quantityPerUnit" VerticalAlignment="Top" HorizontalAlignment="Left" Width="340" /> <TextBox Height="21" Margin="130,104,0,0" Name="unitPrice" VerticalAlignment="Top" HorizontalAlignment="Left" Width="120" /> <Button Height="23" HorizontalAlignment="Left" Margin="130,150,0,0" Name="ok" VerticalAlignment="Top" Width="75" Click="ok_Click">OK</Button> <Button Height="23" HorizontalAlignment="Left" Margin="300,150,0,0" Name="cancel" VerticalAlignment="Top" Width="75" IsCancel="True">Cancel</Button> </Grid> </Window>

  29. private void ok_Click(object sender, RoutedEventArgs e) { if (String.IsNullOrEmpty(this.productName.Text)) { MessageBox.Show(“The product must have a name”, “Error”, MessageBoxButton.OK, MessageBoxImage.Error); return; } decimal result; If (!Decimal.TryParse(this.unitPrice.Text, out result)) { MessageBox.Show(“The price must be a valid number”, “Error”, MessageBoxButton.OK, MessageBoxImage.Error); return; } if (result < 0) { MessageBox.Show(“The price must not be less than zero”, “Error”, MessageBoxButton.OK, MessageBoxImage.Error); return; } this.DialogResult = true; }

  30. Dodavanje novog proizvoda private void addNewProduct() { ProductForm pf = new ProductForm(); pf.Title = “New Product for “ + supplier.CompanyName; if (pf.ShowDialog().Value) { Product newProd = new Product(); newProd.SupplierID = supplier.SupplierID; newProd.ProductName = pf.productName.Text; newProd.QuantityPerUnit = pf.quantityPerUnit.Text; newProd.UnitPrice = Decimal.Parse(pf.unitPrice.Text); supplier.Products.Add(newProd); productsInfo.Add(newProd); this.saveChanges.IsEnabled = true; } }

  31. Izmena podataka o proizvodu private void editProduct(Product prod) { ProductForm pf = new ProductForm(); pf.Title = “Edit Product Details”; pf.productName.Text = prod.ProductName; pf.quantityPerUnit.Text = prod.QuantityPerUnit; pf.unitPrice.Text = prod.UnitPrice.ToString(); if (pf.ShowDialog().Value) { prod.ProductName = pf.productName.Text; prod.QuantityPerUnit = pf.quantityPerUnit.Text; prod.UnitPrice = Decimal.Parse(pf.unitPrice.Text); this.saveChanges.IsEnabled = true; } }

  32. Upis izmena u bazu private void saveChanges_Click(object sender, RoutedEventArgs e) { try { ndc.SubmitChanges(); saveChanges.IsEnabled = false; } catch (Exception ex) { MessageBox.Show(ex.Message, “Error saving changes”); } }

More Related