Tag Archives: LINQ to SQL

Handling with Connection String at Run-Time in developing desktop applications


Almost every desktop application deals with some kind of external memory to save data for further use. The most part of them, use a database. On the other hand an Application needs connection string to connect to the database, for handling its memory. So, how to use connection string and how to manipulate with it, that’s the question which this post wants to answer.

If we want to change the connection string during the application run-time, it is not a simple task, because the connection string is placed in to an application scope that is read only.

The reason why we need to change the connection string is the different settings and environment between users, as well as different environment between developer and end-user. So when we are planning application deployment we must have that in mind, and  provide the implementation custom modification of the connection string.

clip_image002

If we look files of an Application (for example on the picture above) we can see two exe file, and two corresponding configuration files. This is the .NET rule, that every exe file may have only one configuration file.

The structure of configuration file

clip_image004

The picture above shows content of the configuration file and the connection string data. .NET Application can access this data with the API placed in to System.Configuration namespace, by using specific XML schema developed by Microsoft for that purpose.

To access NorthwindConncetionString from the configuration file we can achieve that with the following code:

//Read connection string from configuration file
var connStringFromConfig = System.Configuration.ConfigurationManager.
ConnectionStrings["ConnStringDemo1.Properties.Settings.NorthwindConnectionString"];

If we want to change connection string, exception will throw with the following message:

clip_image005

So the question is how to change connection string anyway?

To change connection string we need to open configuration file with XML API functions, find the connection string and change the data manually then save changes back to file then restart the application. This is in short how to do that, the following code do exactly what we said before:

private bool ChangeConnectionString(string connStringName, string newValue)
{
 try
 {
 //CreateXDocument and load configuration file
 XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

 //Find all connection strings
 var query1 = from p in doc.Descendants("connectionStrings").Descendants()
 select p;

 //Go throught each connection string elements find atribute specified by argument and replace its value with newVAlue
 foreach (var child in query1)
 {
 foreach (var atr in child.Attributes())
 {
 if (atr.Name.LocalName == "name" && atr.Value==connStringName)
 if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
 atr.NextAttribute.Value = newValue;
 }
 }

 doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

 return true;
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 return false;
 }
}

Change connection string for Entity Framework at run-time

As you already know the connection string for Entity Framework is little bit different than the connection string used by DataSet and Lin2SQL. In order to modify the Entity framework connection string the previous code must be modified. The following code modified the entity framework connection string.

private bool ChangeEFConnectionString(string connStringName, string newValue)
{
try
{
//CreateXDocument and load configuration file
XDocument doc = XDocument.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

//Find all connection strings
var query1 = from p in doc.Descendants("connectionStrings").Descendants()
select p;

//Go through each connection string elements find atribute specified by argument and replace its value with newVAlue
foreach (var child in query1)
{
foreach (var atr in child.Attributes())
{
if (atr.Name.LocalName == "name" && atr.Value == connStringName)
if (atr.NextAttribute != null && atr.NextAttribute.Name == "connectionString")
{
// Create the EF connection string from existing
EntityConnectionStringBuilder entityBuilder =
new EntityConnectionStringBuilder(atr.NextAttribute.Value);
//
entityBuilder.ProviderConnectionString= newValue;
//back the modified connection string to the configuration file
atr.NextAttribute.Value = entityBuilder.ToString();
}
}
}

doc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);

return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return false;
}
}

In the previous code we used the EntityConnectionStringBuilder which is very handy in this situation.

The source code for this post you can find on SkyDrive.

Advertisements

WPF i LINQ to SQL III dio, data validation


U prethodnom postu vidjeli smo na koji način možemo manipulirati podacima u smislu sortiranja, grupiranja, te filtriranja podataka. Za ovaj put prezentiraćemo validiranje podataka u WPF odnosno DataValidation. U WPF postoji predefinisan model validiranja podataka tako da svaki tip izveden iz IDataErrorInfo interfejsa podržava validiranje podataka.

Implementacija validacije podataka

Početak ovog posta baziran je na prethodnom primjeru, a potrebno je implementirari validiranje podataka za naš model podataka. Valdaciju podataka moguće je implementirati na različitim konceptialnim modelima aplikacije. U ovom poglavlju validaciju ćemo implementirati na nivou našeg modela baze podataka. Validacija će se sastojati u tome da kad god unesemo datum veći od 1. Januara 2009 godine u datum narudžbe informacija o nepravilnom unosu upozoravaće nas prilikom svakog gubljenja fokusa date kontrole na našem interfejsu. Obzirom da smo validaciju pretpostavili na nivou modela, potrebno je klasu Orders derivirati iz interfejsa IdataErrorInfo da bi iskoristili ugrađeni mehanizam u WPF.

Otvorimo datoteku NorthWindKlase.cs te definišimo parcijanu deklaraciju klase Orders na sljedeći način:

partial class Order : IDataErrorInfo
{
#region IDataErrorInfo Members
 public string Error
  {
   get { return null; }
  }
 public string this[string columnName]
  {
   get
    {
      if (columnName == "OrderDate")
         if (OrderDate > newDateTime(2009, 1, 1))
           return "Datum nije validan. Molimo ispravite datum.";
    return null;
   }
  }
#endregion
}

Klasa Order izvedena je iz dva interfejsa koja su definisana u dizajnerskog datoteci. U cs datoteci ovu klasu izvodimo iz još jednog interfejsa IdataErrorInfo. Ovaj interfejs obezbjedjuje implementaciju validacije podataka u WPF. Dvije implementacije je potrebno izvršiti i to za Property Error koja u ovom slučaju nije potrebna, a inače služi kada upravljamo sa više pogrešaka koje se mogu pojaviti u klasi Orders. Druga metoda je indexer u kojem prvo provjeravamo da li je vrijednost indexera posmatrani naziv kolone OrderDate. Zatim tekuću vrijednost provjeravamo, i ako vrijednost ne zadovoljava naše definisane kriterije vraćamo neprazan string koji u biti sadržava poruku pogreške.

Napomena: Kada u polju datuma ne postoji nikakva vrijednost (prazan string) ili vrijednost koja ne predstavlja datum, validacija takvih podataka je već implementirana tako da se takvi podaci neposmatraju ovom implementacijom. Naša validacija OrderDate kolone se sastoji u tome da ako smo definsiali datum koji je veći od 1. Januara 2009 godine, izbacuje se pogrešaka. Kada smo implementirali logiku validacije podataka u bussiness layeru, logiku je potrebno povezati sa UI kontrolama, odnosno sa TextBox kontrolom koja prikazuje OrderDate. Kada želimo da povežemo validaciju sa bilo kojom UI kontrlom postavljamo Property ValidatesOnDataErrors=True. Sa ovim je cijela implementacija validacije podataka iz bussiness layer povezana sa UI kontrolom.

Kada u ovoj fazi implementacije pokrenemo naš primjer i kad u polje OrderDate unesemo datum koji je veći od datuma 1. Januar 2009 godine, mehanizam validacije podataka se pokreće i dobijamo sljedeći sliku.

image_020720093C88EA80

Sa slike vidimo da je tekstualna kontrola Order Date promjenila boju ivice na crvenu. Ovo je standardni šablon koji se koristi kada se pokrene mehanizam validacije. Medjutim, sa crvenom bojom ivice mi ništa više ne znamo od pogreške. Za ovaj primjer implementirat ćemo šablon koji će tekst pogreške koji je uhvaćen u bussiness layeru prikazati kao tooltip naše kontrole. Da bi ovo implementirali potrebmo je definisati Stil validacije podataka. Stil validacije podataka definišemo na sljedeći način:

<!--Šablon validacije podataka-->
<Style  TargetType="TextBox">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip"
                    Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                    Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
    </Style.Triggers>
</Style>

U biti gornja implementacija je implementacija stila za TextBox kontrolu koja u sebi sadrži implementaciju Triger (okidača) kad postoji pogreška u validaciji podataka. Kada se desi tada vrijednost ToolTipa date kontrole ima vrijednost teksta pogreške.

Sada kad pokrenemo aplikaciju te unesemo pogrešan datum kao u prethodnom primjeru, te odnesemo miša do date kontrole, pojavljuje se tooltip sa tekstom pogreške.

clip_02072009image002_6B0ECD95

Kada smo definisali Stil za validaciju podataka za textbox kontrolu nismo ga definisali sa ključnom nazivom (x:Key=”stilValidacije), što onda znači da dati stil automatski podešava sve textbox kontrole.

Sa ovim smo završili tutorijal o validaciji podataka.Izvorni kod za ovaj primjer možete skinuti sa ovog linka.

WPF i LINQ to SQL II dio- grouping, filtering, sorting


U prethodnom postu smo vidjeli jedan od načina povezivanja WPF aplikacije sa bazom podataka preko LINQ to SQL. Naše putovanje ide dalje, a ovaj put obradićemo grupiranje, filtriranje i sortiranje. Tutorijal startamo tamo gdje smo stali u prethodnom postu.

Grupiranje podataka

Za razliku od WindowsFormsa u WPF je moguće na vrlo jednostavan način implementirati grupiranje podataka u listbox kontroli. Obzirom da naša listbox kontrola prikazuje samo jednu stavku potrebno ju je kastomizirati. Da bi prikazali više stavki (više kolona i tabele) u listbox kontroli potrebno je implementirati šablon podataka odnosno DataTemplate. Data template nije ništa drugo nego struktura u kojoj je definisano kako treba da izgleda pojedinačna stavka u listi. Kako bi implementirali grupiranje potrebno je, takodjer definisati šablon grupiranja podataka.

U listbox kontroli definisaćemo DataTemplate koji će prikazati DateOrder i ShipPostalCode, a grupiranje ćemo definisati po DateOrder. DataTemplate prikazan je na sljedećoj slici:

<DataTemplate x:Key="sablonPodataka">
    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding Path=OrderDate}"/>
        <TextBlock Text="{Binding Path=ShipPostalCode}"/>
    </StackPanel>
</DataTemplate>

Gornji listing prikazuje StackPanel u kojem se vertikalno poravnavaju dvije tektualne kontrole koje su povezane sa kolonama OrderDate i ShipPostalCode.

DataTemplate grupirane liste definisan je sljedećim DataTemplateom

<DataTemplate x:Key="sablonGrupiranihPodataka">
    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="Red"/>
    </StackPanel>
</DataTemplate>

Ovdje je nešto drugačija situacija. Zaglavlje grupiranja sastoji se samo od jedne tekstualne kontrole ali ova kontrola je povezana sa nazivom osobine (PropertyName) objekta PropertyGroupDescription klase. Ova dva šablona definisali smo u resursu Windowsa, da bi bili dostupni u kontrolama koje su definisane. Definisane šablone potrebno je još povezati sa listbox kontrolom. Obzirom da listbox kontrola po defaultu prikazuje samo jednu stavku i to onu koja je definisana preko DisplayMemberPath osobine, potrebno je ovu osobinu zamjeniti sa novom ItemTemplate koja ima referencu na DataTemplate koji smo definisali na samom početku.

Pored toga, listbox kontroli potrebo je definisati Stil grupiranja koji će imati referencu na drugi šablon kojeg smo formirali. Sve rečeno prikazano je na listingu:

<ListBox Name="listBox1" Grid.RowSpan="6" Grid.Row="3"
         IsSynchronizedWithCurrentItem="True"
         ItemsSource="{Binding Source={StaticResource listaNarudzbi}}"
         ItemTemplate="{StaticResource sablonPodataka}" Grid.ColumnSpan="2">
    <ListBox.GroupStyle>
        <GroupStyle HeaderTemplate="{StaticResource sablonGrupiranihPodataka}" />
    </ListBox.GroupStyle>
</ListBox>

Kada smo definisali prethodne korake naša aplikacija je spremna za grupiranje podataka. Sada je još potrebno implementirati logiku odnosno opciju za grupiranje podataka. U tom smislu definisaćemo Checkbox dugme kojim ćemo grupirati odnosno degrupirati podatke u listbox kontroli. CheckBox dugme postavićemo kao na slici dolje, te mu implementirati dogadjaje Checked i UnChecked .

image

Implementacija dogadjaja sastoji se u formiranju PropertyGroupDescription objekta i postavljanjem Naziva grupirane kolone OrderDate. Zatim novoformirani objekat pridodajemo u kolekciju grupiranja koja je definisana u defaultView objektu.

Kada želimo grupiranje ukloniti potrebno je iz kolekcije izbaciti objekt za grupiranje. Implementacija se nalazi na sljedećem listingu.

//Grupiranje podataka
private void button3_Checked(object sender, RoutedEventArgs e)
{
    PropertyGroupDescription groupDesc = new PropertyGroupDescription("OrderDate");
    defaultView.GroupDescriptions.Add(groupDesc);
}
//De grupiranje podataka
private void button3_Unchecked(object sender, RoutedEventArgs e)
{
    defaultView.GroupDescriptions.Clear();
}

Pokrenimo aplikaciju te isprobajmo kako grupiranje radi.

Filtriranje podataka

Sljedeća implementacija sastoji se u filtriranju podataka. Filtriranje podataka postižemo definišući osobinu (Property) Filter objekta defaultView. Za ovu implementaciju definisaćemo edit kontrolu koja će filtrirati narudžbe po poštanskom broju (ShiPostalCode). Prilikom kucanja poštanskog broja stavke u listbox kontroli će se filtrirati na osnovu unešenog broja. Edit kontrola prikazana ja na sljedećoj slici:

image

Implementacija filtriranja stavki po poštanskom broju prikazan je na sljedećem listingu:

//Filtriranje podataka u listi
private void textBox6_TextChanged(object sender, TextChangedEventArgs e)
{
    string text = this.textBox6.Text.ToLowerInvariant();
    if (defaultView.CanFilter)
        defaultView.Filter = delegate(object obj)
        {
            Order narudzba = obj as Order;

            if (narudzba != null && narudzba.ShipPostalCode != null)
                return narudzba.ShipPostalCode.ToLowerInvariant().Contains(text);
            return false;
        };
}

Filter smo definisanli delagatom koji za parametar uzima narudžbu iz liste, te provjerava da li sadrži definisani text, te vraća true ako postoji traženi text, inače vraća false.

Sortiranje podataka

Slično kao i kod grupiranja sortiranje definišemo preko objekta ListCollectionView podešavanje propertya SortDescriptions. Sljedeći listing prikazuje sortiranje po datumu te u drugoj metodi uklanjamo sortiranje definisano prethodno.

//Sortiranje po datumu
private void checkBox1_Checked(object sender, RoutedEventArgs e)
{
   SortDescription sortiranjePoDatumu=new SortDescription("OrderDate",ListSortDirection.Ascending);
   defaultView.SortDescriptions.Add(sortiranjePoDatumu);
}
//Resetovanje sortiranje na početno
private void checkBox1_Unchecked(object sender, RoutedEventArgs e)
{
    defaultView.SortDescriptions.Clear();
}

Na sljedećoj slici prikazan je checkbox preko kojeg definišemo sortiranje podataka, Kada otkačimo checkbox sortiranje se resetuje.

image

Ovim smo završili našu implementcaiju grupiranja i sortiranja podatka. Izvorni kod za ovaj primjer dat je na ovom linku.

WPF i LINQ to SQL


U narednih nekoliko postova biće riječi o novoj microsoftovoj tehnologiji za razvoj windows aplikacija Windows Presentation Foundation, kao i razvoj aplikacija koje se oslanjaju na baze podataka preko LINQ to SQL i LINQ to Entity. Biće prikazani osnovni modeli aplikacije sa prikazom implementacije osnovnih CRUD operacija razvijani na WPF tehologiji.

Kratki uvod

WPF je nova tehnologija razvoja windows aplikacija bazira na DirectX grafičkoj biblioteci, umjesto klasičnih GDI aplikacija na kojim su se zasnivale sve dosadašnje microsoftove tehnologije. Ovim prelazom omogućen je razvoj windows grafičkih interfejsa na sličan način kako se to radi sa web aplikacijama. U tom smislu razvijen je novi programski jezik XAML (čitaj zaml) koji je sastavni dio .NET Frameworka. Sa razvojem XAML razvijen je novi skup programskih rješenja koja pomažu u dizajnu windows aplikacija nazvan Expression Studio. Ovaj paket aplikacija uključuje Expression Blend, Expresion Design i druge aplikacije kojim razvijamo GUI dok logiku ispod kontrola GUI-a razvijamo u klasičnim razvojnim alatima poput Visual Studia. Sa ovim se razdvojio dizaj i logika aplikacije te uvela nova tehnologija razvoja aplikacija kao i sistematičnija kolaboracija izmedju dizajnera i developera.

Informacije o WPF mogu se pronaći na internetu sa vrlo različitim novoima predznanja, te u ovom vrlo kratkom uvodu želio sam samo natuknuti neke od osnovnih značajki ove tehnologije. Svakako prije čitanja ovih postova potrebno je minimalno predznanje o WPF tehnologiji. Prvi post će biti prikazan u obliku tutorijala s kojim ćemo implementirati jednostavan primjer povezivanja baze podataka sa WPF aplikacijom, te upoznati osnovne operacije umetanja, modifikacije i brisanja zapisa iz baze podataka. Primjer će također prikazati neke od metoda na koji način koristimo Visual Studio 2008 i Microsoft Expression Blend u razvoju aplikcija. Za ovaj i primjere koji će biti prikazani u narednim postovima, potrebna je instalacija Visual Studio 2008 SP1, Expresion Blend 2, Microsoft SQL Server 2005 ili 2008,NorthWind baza podataka, a svi se oni mogu skinuti na microsoftovim stranicama, kao i u besplatin express verzijama.

NorthWind WPF primjer

Prije početka potrebno je NorthWind bazu podataka instalirati na server, kako bi se kroz Visual studio mogao formirati model baze podataka.

Pokrenimo VS 2008 te formirajmo novi WPF projekat kao na sljedećoj slici.

Nakon formiranja WPF projekta potrebno je formirati LINtoSQL model northwind baze podataka. Način na koji formiramo model možete pogledati na jednom od mojih prethodnih blog postova. Ovaj put naš model se sastoji od sljedećih tabela baze podataka: Customer, Employee, Order, Order_Detail. Sada naš projekat izgleda kao na slici 2.

U solucijskog exploreru možemo vidjeti da se naš projekat sastoji od Window1.xaml i korespodentne cs datoteke, App.xaml te korespodentne cs datoteke, kao i novoformiranog modela baze podataka kojeg smo objašnjavali u prethodnim postovima. Da bi NorthWind model baze podataka inkorporirali sa aplikacijom potrebno je dodatno implementirati logiku.

Kada sa prethodne slike desnim klikom miša odaberemo opciju View Code dobijamo implementaciju klase NorthWindKlaseDataContext. U klasi je potrebno implementirati metode za izvlačenje svih Narudžbi (Odrers), Dobavljača i Zaposlenika. Implementacija je prikazana u sljedećoj slici:

namespace NorthWindWPFPrimjer
{
    using System.Collections.ObjectModel;
    using System.Linq;

    partial class NorthWindKlaseDataContext
    {
        public ObservableCollection<Order> IzvuciNarudze()
        {
            var query = from p in Orders select p;
            return new ObservableCollection<Order>(query);
        }
        public ObservableCollection<Customer> IzvuciDobavljace()
        {
            var query = from p in this.Customers select p;
            return new ObservableCollection<Customer>(query);
        }
        public ObservableCollection<Employee> IzvuciZaposenike()
        {
            var query = from p in this.Employees select p;
            return new ObservableCollection<Employee>(query);
        }
    }
}

Važna napomena: Nemojte ni u kom slučaju using naredbe postavljati iznad prostora imena NorthWindWPFPrimjer jer će vam se izgubiti datoteka dizajnera i vaš model će nestati. Nažalost ovo je bug koji se nalazi u Visual Studio 2008 SP1.

Na ovaj način implementirali smo metode za izvlačenja podataka iz baze podataka. Sada je na redu da to implementiramo u window1.xaml datoteci. Da bi prikazali podatke o naružbama u window1.xaml datoteci potrebno je formirati objekat ObjectDataProvider kojim ćemo povezati kontrole za prikaz narudžbi. Naravno, ovaj tutorijal neće ulaziti u detalje i objašnjenja svih pojmova i tipova podataka, jer to i nije svrha. Možemo kazati da ObjectDataProvider obuhvata i formira objekat koji omogućuje povezivanje sa izvorom podataka. U WPF izvor podataka mogu biti klasični izvori podataka: vanjska baza podataka, XML datoteka, in memory kolekcija podataka, kao i svaka windowsova standardna ili kastomizirana kontrola, odnosno bilo koji .NET objekat. Ovo je i jedan od najvažnijih aspekata ove tehnologije. Kako smo na samom početku rekli XAML kao novi prograski jezik nije zamjena za klasične .NET jezike, on u biti predstavlja jedno proširenje .NET programskim jezicima, tako da sve što se može implementirati pomoću XAML-a možemo to učiniti i sa C# odnosno VB jezikom, dok obrnuto ne vrijedi.

Prilikom razvijanja aplikacije u WPF, implementacija u XAML datoteci označava deklarativnu implementaciju dok se implementacija u korespondentnom C# ili VB jeziku zove code-behind implementacija.

Dizaj aplikacije

Sada je potrebno našu aplikaciju dizajnirati, u principu potrebno je definisati kontrole koje će kasnije biti povezane sa bazom podataka odnosno sa tabelama i kolonama. Dizaj aplikacije sastoji se od jedne ListBox kontrole u kojoj će biti prikazane sve narudžbe, dok će sa desne strane biti polja u kojim će biti prikazani detalji svake narudžbe pojedinačno. Donja slika prikazuje dizaj prozora.

Sa desne strane postavili smo detalje svake narudžbe od kojih je najinteresantniji dio kolone Customer i Employee koji predstavljeju vanjske ključeve za tabele Customer i Employee. Preko ComboBoxa ostvarićemo ovu relaciju, gdje ćemo u combobox listi prikazati sve partnere (Customers) i zaposlenike (Employees). Obzirom da u standardnom setu kontrola ne postoji kontrola izbora Datuma i Vremena koristimo običnu edit kontrolu Text Box za prikaz datuma.

Cjelokupan dizajn gornjeg prozora uradili smo u XAML datoteci dok ćemo logiku aplikacije implementirati u cs datoteci ili tzv. Code-behind datoteci. Ovo je klasičan primjer upotrebe WPF tehnologije. Dizaj aplikacije implementirati u XAML, a logiku u code-behind datoteci.

Povezivanje sa bazom podataka

Da bi povezali aplikaciju sa bazom podataka potrebno je formirati objekat klase NorthWindKlaseDataContext preko kojeg ćemo vršiti upit prema bazi podataka. Ovdje ćemo pokazati dva načina implementacije. Jedan način je da u code-behind formiramo objekat te povežemo kontrole sa izvorom podataka, a drugi da u XAML-u uradimo isto. Oba načina su ispravna i nema nikave razlike u pogledu performansi. Na sljedećem ispisu prikazan je code-behind način. Listing datoteke Window1.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace NorthWindWPFPrimjer
{
    public partial class Window1 : Window
    {
        NorthWindKlaseDataContext dx = new NorthWindKlaseDataContext();
        public Window1()
        {
            InitializeComponent();

            listBox1.ItemsSource = dx.IzvuciNarudze();
            listBox1.DisplayMemberPath = "OrderID";

            Binding binding = new Binding();
            binding.Source = listBox1.ItemsSource;
             //OrderID
            binding.Path = new PropertyPath("OrderID");
            textBox1.SetBinding(TextBox.TextProperty, binding);

            //OrderID
            Binding binding1 = new Binding();
            binding1.Source = listBox1.ItemsSource;
            binding1.Path = new PropertyPath("CustomerID");
            comboBox1.ItemsSource = dx.IzvuciDobavljace();
            comboBox1.DisplayMemberPath = "ContactName";
            comboBox1.SelectedValuePath="CustomerID";
            comboBox1.SetBinding(ComboBox.SelectedValueProperty, binding1);

            //EmployeeID
            Binding binding2 = new Binding();
            binding2.Source = listBox1.ItemsSource;
            comboBox2.ItemsSource = dx.IzvuciZaposenike();
            comboBox2.DisplayMemberPath = "FirstName";
            comboBox2.SelectedValuePath = "EmployeeID";
            binding2.Path = new PropertyPath("EmployeeID");
            comboBox2.SetBinding(ComboBox.SelectedValueProperty, binding2);

            Binding binding3 = new Binding();
            binding3.Source = listBox1.ItemsSource;
            //OrderDate
            binding3.Path = new PropertyPath("OrderDate");
            textBox2.SetBinding(TextBox.TextProperty, binding3);

            Binding binding4 = new Binding();
            binding4.Source = listBox1.ItemsSource;
            //ShipVia
            binding4.Path = new PropertyPath("ShipVia");
            textBox3.SetBinding(TextBox.TextProperty, binding4);

            Binding binding5 = new Binding();
            binding5.Source = listBox1.ItemsSource;
            //Freight
            binding5.Path = new PropertyPath("Freight");
            textBox4.SetBinding(TextBox.TextProperty, binding5);

            Binding binding6 = new Binding();
            binding6.Source = listBox1.ItemsSource;
            //ShipPostalCode
            binding6.Path = new PropertyPath("ShipPostalCode");
            textBox5.SetBinding(TextBox.TextProperty, binding6);
        }
    }
}

Pokrenimo aplikaciju iz VS i dobićemo sljedeću sliku:

Ako pokušamo da selektujemo drugu stavku iz liste automatski cemo dobti druge vrijednosti u desnim kontrolama. Ovo automatsko sihroniziranje selektovane stavke iz liste i kontrola obezbjedjeno je formiranjem ObservableCollection klase te osobine liste IsSynchronizedWithCurrentItem=”True”.

Sljedeći listing prikazuje prethodno ali implementirano u XAML-u.

<Window x:Class="NorthWindWPFPrimjer.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:NorthWindWPFPrimjer"
    Title="NorthWind Prijmer" Height="357" Width="514" Closing="Window_Closing">
    <Window.Resources>
        <!--Formiranje ObjectDataProvidera preko NazivaMetode bez parametara-->
        <ObjectDataProvider x:Key="listaNarudzbi"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciNarudzbe"/>
        <ObjectDataProvider x:Key="listaPartnera"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciDobavljace"/>
        <ObjectDataProvider x:Key="listaZaposlenika"
                            ObjectType="{x:Type local:NorthWindKlaseDataContext}" MethodName="IzvuciZaposenike"/>
    </Window.Resources>
    <Grid>
        <!--Rešetka za raspored kontrola-->
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="40" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="100" />
            <ColumnDefinition Width="150" />
        </Grid.ColumnDefinitions>
        <!--List box kontrola za naslovom-->
        <TextBlock Margin="0,0,0,0" Name="textBlock1" Text="Lista Naružbi"
                   VerticalAlignment="Center" HorizontalAlignment="Center"
                   FontSize="16" FontWeight="Bold" Foreground="Chocolate" />
        <ListBox Name="listBox1" Grid.RowSpan="7" Grid.Row="1" IsSynchronizedWithCurrentItem="True"
                 ItemsSource="{Binding Source={StaticResource listaNarudzbi}}" DisplayMemberPath="OrderID" />

        <!--Labele za oznakama polja za editovanje-->
        <Label Grid.Column="1" Margin="10,12,0,0" Name="label1" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">OrderID:</Label>
        <Label Margin="6,6,4,6" Name="label2" Grid.Column="1" Grid.Row="1" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Customer:</Label>
        <Label Margin="6,12,4,0" Name="label3" Grid.Column="1" Grid.Row="2" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Employee:</Label>
        <Label Margin="6,6,4,6" Name="label4" Grid.Column="1" Grid.Row="3" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Order Date:</Label>
        <Label Margin="6,6,4,6" Name="label5" Grid.Column="1" Grid.Row="4" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Ship Via:</Label>
        <Label Margin="6,6,4,6" Name="label6" Grid.Column="1" Grid.Row="5" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Freight:</Label>
        <Label Margin="6,12,4,0" Name="label7" Grid.Column="1" Grid.Row="6" HorizontalContentAlignment="Right"
               VerticalContentAlignment="Center">Postal Code:</Label>
        <!--Kontrole za modifikaciju i prikaz kolona narudžbe-->
        <TextBox Margin="0,8,0,8" Grid.Column="2" Grid.Row="0" Name="textBox1"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=OrderID}" />
        <ComboBox Margin="0,8,0,8" Grid.Column="2" Grid.Row="1"  Name="comboBox1"
                  ItemsSource="{Binding Source={StaticResource listaPartnera}}"
                  SelectedValuePath="CustomerID"
                  SelectedValue="{Binding Source={StaticResource listaNarudzbi}, Path=CustomerID}"
                  DisplayMemberPath="ContactName"/>
        <ComboBox Margin="0,8,0,8" Name="comboBox2" Grid.Column="2" Grid.Row="2"
                  ItemsSource="{Binding Source={StaticResource listaZaposlenika}}"
                  SelectedValuePath="EmployeeID" SelectedValue="{Binding Source={StaticResource listaNarudzbi},  Path=EmployeeID}"
                  DisplayMemberPath="FirstName"/>
        <TextBox Margin="0,8,0,8" Name="textBox2" Grid.Column="2" Grid.Row="3"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=OrderDate }" />
        <TextBox Margin="0,8,0,8" Name="textBox3" Grid.Column="2" Grid.Row="4"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=ShipVia}" />
        <TextBox Margin="0,8,0,8" Name="textBox4" Grid.Column="2" Grid.Row="5"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=Freight}" />
        <TextBox Margin="0,8,0,8" Name="textBox5" Grid.Column="2" Grid.Row="6"
                 Text="{Binding Source={StaticResource listaNarudzbi}, Path=ShipPostalCode}" />
        <!--Dugmad za brisanje i dodavanje stavki u bazu podataka-->
        <Button Grid.Column="2" Grid.Row="7" Margin="65,6,23,10" Name="button1">Obriši</Button>
        <Button Margin="21,6,17,10" Name="button2" Grid.Column="1" Grid.Row="7" Click="button2_Click">Nova</Button>
    </Grid>
</Window>

Podcrtani XAML kod označava novi kod koji smo dodali pri povezivanju kontrola sa bazom podataka.

Na samom početku definisali smo ObjectDataProvide preko NazivaMetode, i to za svaku tabelu. ObjectDataProvider uvijek se definiše unutar resursa Kontrole roditelja te na taj način objekt postaje vidljiv u svim kontrolama koje pripadaju datom roditelju.

Definisanje logike aplikacije

Prethodno smo definisali model baze podataka preko LINQtoSQL dizajnera, dodatno implementirali poslovnu logiku modela. Zatim smo dizajnirali našu aplikaciju na način da smo definisali raspored i vrste kontrola. Poslije toga povezali smo bazu podataka sa aplikacijom i prikazali podatke preko kontrola.

Za ovaj tutorijal ostaje da implementiramo CRUD operacije odnosno modifikaciju podataka, brisanje i dodavanje redova u bazu podataka. Za početak implementirajmo modifikaciju podataka na način da kad se aplikacija zatvori, da se provjeri da li su podaci mijenjani u odnosu na originalne podatke i baze podataka te na osnovu toga izvršiti modifikaciju baze podataka.

Za ovo nam je potrebno implementirati Closing dogadjaj.

Implementacija unosa novog reda u tabeli

Da bi uopće manipulisali prikazanim podacima u našoj aplikaciji potrebno je dobiti referencu na ListCollectionView a koja predstavlja tekuće podatke u našoj aplikaciji. Takodjer ako smo povezivanje uradili u XAML-u potrebno je definisati referencu na objekat NorthWindKlaseDataContext, a koju ćemo dobiti iz ObjectDataProvidera.

private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
 {
  //U koliko je u toku zatvaranja prozora jos uvijek postojala modifikacija odredjene stavke
  //potrebo napraviti Refresh da bi sve promjene bile aktualizirane
  defaultView.Refresh();

  //Provjera da li postoji bilo kakva promjena koja bi se trebala zapisati u bazu podataka
  int br = dataContext.GetChangeSet().Deletes.Count +
           dataContext.GetChangeSet().Inserts.Count +
           dataContext.GetChangeSet().Updates.Count;

  if (br > 0)
    {
      if (MessageBox.Show("Da li želite pohraniti nastale promjene?",
           "WPF Primjer", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
        {
            dataContext.SubmitChanges();
        }
    }
 }

Iz tog razloga potrebno je na novou Windows objekta formirati članove na sljedeći način:

//Referenca na DefaultView koja je definisan u list kontroli
ListCollectionView defaultView;
//Referenca da DataContext
NorthWindKlaseDataContext dataContext;

Prilikom učitavanja aplikacije odnosno pozivanja dogadjaja Loaded potrebno je ove reference definisati:

private void Window_Loaded(object sender, RoutedEventArgs e)
 {
   //Referenca na DefaultView
   defaultView = (ListCollectionView)CollectionViewSource.GetDefaultView(listBox1.ItemsSource);
   dataContext = (NorthWindKlaseDataContext)(FindResource("listaNarudzbi") as ObjectDataProvider).ObjectInstance;

    Debug.Assert(defaultView != null);
    Debug.Assert(dataContext != null);
 }

Dodavanje nove stavke vrši se jednostavno na sljedeći način:

//Dodavanje nove stavke
private void button2_Click(object sender, RoutedEventArgs e)
 {
   //dodavanje nove stavke
   Order newOrder = (Order)defaultView.AddNew();
   //novoformiranu stavku pohraniti u bazu podataka prvi put kada se pozove SubmitCange
   dataContext.Orders.InsertOnSubmit(newOrder);

 }

Pozivom AddNew metode iz defaltView i novu stavku potrebno je registrovati u DataContext da bi se pohranile promjene. Kada pokrenemo aplikaciju i kliknemo da dugme Dodaj, u listBox na kraju se pojavi nova stavka. Sa desne strane popunimo polja. Prilikom zatvaranja aplikacija pojavljuje se upit za pohranu podataka.

Implementacija brisanja stavke

Birisanje stavke iz liste vršimo listingom prikazanim na sljedećoj slici:

//Brisanje tekuce stavke
private void button1_Click(object sender, RoutedEventArgs e)
  {
    if (MessageBox.Show("Da li želite obrisati tekuću stavku?",
         "WPF Primjer", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
          return;
    //Prvo je potrebno objekat da se objekat oznaci obrisan u DataContext
    dataContext.Orders.DeleteOnSubmit((Order)defaultView.CurrentItem);
    //Označeni objekat brisemo iz DafaulView
    defaultView.Remove(defaultView.CurrentItem);

  }

Pokrenemo aplikaciju te klikom na dugme Obriši pojavljuje se poruka za potvrdu brisanja stavke.

Zaključak

Ovim jednostavnim primjerom prikazali smo jedan od načina implementacije LINQ to SQL u WPF. Sljedećim postovima obradićemo manipulaciju sa podacima u smislu sortiranja grupiranja podataka. Također u narednim postovima govorićemo o konvertorima, kastomizaciji listbox kontrole i sl.

Izvorni kod za ovaj primjer možete skinuti sa ovog linka.

LINQ- VII LINQ TO SQL


…nastavak prethodnog posta

Posebne napomene uz LINQ to SQL dizajner

LINQ to SQL je jednostavni O/R dizajner i podržava mapiranje 1:1. To znači da dizajner mapira jednu klasu (entitet) i samo jednu Tabelu ili View. Složeno mapiranje objekata, poput mapiranja klasa i spojenih tabela nije za sada podržano. LINQ to SQL dizajner jednostrano generira kod. Ako napravimo ručne promjene u izvornom kodu to se neće reflektirati na dizajner. Samo promjene napravljene preko dizajnera u dizajnerskom modu reflektuju se u izvorni kod.

Modifikacija podataka sa LINQ To SQL

U dosadašnjim primjerima vidjeli smo kako uzvući podatke iz DB, koristeći LINQ to SQL. Takodjer, vidjeli smo kako izvlačiti podatke iz relacijski-povezanih tabela. U ovom dijelu vidjećemo na koji nači vršimo modifikaciju podataka. Modifikacija podataka se odvija preko klase DataContext.

Klasa DataContext

DataContext je centranla klasa koja upravlja svim transakcijama koje se dešavaju. Ova klasa je odgovorna za pristup Serveru DB, prosljedjivanju SQL upita, monitoring nad modificiranim podacima na klijentu (ObjectTracking), rješavanju konflikata kod slanja podataka na Server i mnogo više. Kada pogledamo izvorni kod koji je dizajner generirao za ovu klasi nećemo naći puno toga. Ona se uglavnom sastoji od nekoliko konstruktora preko kojih instanciramo objekat , te članove (fields) koji su entiteti modela. Ova klasa se u pravilu uvijek koristi kao izvedena jer tim načinom dobijamo tipizirani (strongly typed) DataContext.

Metode koje sadržava ova klasa možemo podijeliti na sljedeće:

· Metoda za manipulaciju sa DB

· Metode za izvršavanje upita

· SubmitChanges() – metoda za slanje podataka u DB

· Opcije za rješavanje konflikata prilikom slanja podataka u DB

· Transakcije

SabmitChanges()

Prilikom bilo kakvih promjena podataka na klijentu klasa DataContext sadrži mehanizam praćenja svih tih promjena. Ovaj mehanizam se zove CHANGE PROCESSOR, i zadužen je za praćenje promjena podataka na klijentu. Kada pozovemo SubmitChanges(), klasa DataContex će pokušati pretvoriti sve promjene u adekvatne upite i prosljediti SQL Serveru. Prilikom generiranja upita DataContext će na osnovu generiranog DB modela uvažavajući sve relacije izmedju klasa i sva ograničenja kolona te primarne i vanjske ključeve, generirati SQL upite, koji će sekvencijalno slati na server. Prije samog slanja formira se transakcija koja se prekida i vraća u prvobitno stanje podatke, ako najmanje jedan upit bude neuspješan. Tada se izbacuje izuzetak i upozorava korisnik da promjene nisu uspješno prosljeđene Serveru.

Obzirom da transakcija nije prošla, DataContext ima sve informacije o upitima koji stvaraju konflik. Na taj način obezbjeđeno je pozivanje ove metode više *** sa korekcijama konflikata. Kada poslije korigiranja promjena, metoda uspije bez izuzetaka DataContext se resetuje i iz početka prati novonastale promjena na klijetu. Više informacija oko ove metode i klase možete naći na kraju ovog članka u referencama. Slanje podataka na server i način na koji se to odigrava zavisi od osobina (properties) svake klase u modelu, koje su prethodno prikazane. Naredni primjer pokazaće način na koji manipulišemo podacima iz DB, odnosno korištenje standardnih SQL naredbi Select, Insert, Update, Delete ili jednostavno CRUD.

Primjer sa sastoji od modela NorthWind baze podataka. Ako je ne posjedujete možete je skinuti sa ovog linka.

1. Formirajte novi projekat u VS 2008, C# programskijezik, Windows Forms Application tip projekta. Slično prethodnim primjerima

2. Formirajte LINQ to SQL dbml model baze podataka, te mapirajte tabele kao na slici.

clip_image002

3. Otvorite cs datoteku Form1, te iz usidrenog prozora DataSource importujete prethodne tabele kao objekte. Nakon importovanja DataSource prozor izgleda kao na slici.

clip_image004

4. Povucite i spustite Tabelu Order, a iz njenog drveta povucite i spstite tabelu Order_Detail. Rezultat bi trebao da izgleda kao na sljedećoj slici:

clip_image006

5. Implementirajte dogadjaj FormLoad, te privatni član klase Form1, dcNorthWind klase NorthWindKlaseDataContext.

6. Napišite implementaciju dogadjaja kao na sljedećoj slici.

clip_image008

Obzirom da smo LINQ to SQL modelom definisali i relacije izmedju klasa, nije potrebno posebno implementirati upite za svaku tabelu. Dovoljo je implementirati upit za tabelu Order, a kako smo vidjeli u prethodnom primjeru (prethodni post), podaci za ostale tabele se generiraju iz tabele Order.

7. Pokrenite aplikaciju. Rezultat bi trebao da izgleda kao na sljedećoj slici.

clip_image010

Pomjerajući se kroz tabelu Order, relevantni podaci u tabeli Order_Details se pojavljuju, odnosno implementacija relacije Master/Detail je realizirana.

Modifikacija podataka

Da bi mogli modificirati podatke u tabelama potrebno je da se implementira opcija Save (neaktivna sličica i navigacijskog toolbara clip_image012). Da bi implementirali spremanje podataka u DB, dva *** kliknimo na prethodno dugme i implementirajno metodu kao na sljedećoj slici, te osobinu Enable stavimo na TRUE. Bez obzira kako kompleksna forma bila, metodom SubmitChange(), LIN to SQL pohranjuje kako jednostavne tako i kompleksne hiearhijske zapise u bazu.

clip_image014

clip_image016

Prethodni primjer unosa novih stavki u relaciju Master/Detail prezentira svu jačinu LINQ to SQL tehnologije. Za ovakav primjer bilo nam je potrebno puno više vremena i živaca, koristeći DataSet ili DataTable.

LINQ TO SQL i Storne Procedure

Jednostavnost i ušteda na implementaciji koju smo vidjeli u prethodnom primjeru ništa nije drugačija i kompleksnija i kod korištenja stornih procedura. Storne procedure kao što smo vidjeli mapiraju se u desni dio prozora dizajnera, povlačeći i spuštajući stornu proceduru iz baze podataka.

Sljedeći primjer pokazuje korištenje stornih procedura sa LIN to SQL. U prethodni primjer mapirajmo stornu prceduru kao na slici.

clip_image018

Implementirajmo novu formu SPForm2, te njen dogadjaj FormLoad, kao na slici. U Početnoj formi implementirajte Dugme Pozivanje SP, te dogadjaj ButtonClick.

clip_image020

Implementacija Dugmeta Pozivanje SP, izgleda kao na sljedećoj slici:

clip_image022

Kompajlirajete i pokreite aplikaciju, nakon klika na dugme Pozivanje SP, pojavljuje se prozor sličan kao na slici:

clip_image024

Izvorni kod za ovaj post možete skinuti odavde.

Reference:

1. http://msdn2.microsoft.com/en-us/vcsharp/aa336746.aspx

2. http://weblogs.asp.net/scottgu/

3. http://blogs.msdn.com/somasegar/

4. http://channel9.msdn.com

5. http://aspalliance.com/1331_Using_LINQ_to_SQL__Part_2.all

LINQ – VI DIO LINQ TO SQL


…nastavak prethodnog posta

DB Model

Nakon uspješno izvedenog tutorijala pokušat ću objasniti način na koji radi LINQ to SQL.

Prva stvar koji smo uradili bila je formiranje modela DB. Procedura se ništa ne razlikuje od one kojom formiramo novu formu ili neku kontrolu. Kada smo formirali LINQ to SQL datoteku, VS dizajner je prikazao prazan model, koji se sastoji od dva podjeljena prozora lijevi prozor u kojem modeliramo klase odnosno entitete, a u drugi desni importujemo funkcije i storne procedure. Funkcija modela baze podataka je mapiranje prvenstveno tabela iz DB, koje u .NET nazivamo klasama ili entitetima. Svaki entitet je mapirana tabela, čije osobine (Properties) mapiraju kolone iz dotične tabele. I na kraju svaka instanca klase je jedan red (vrsta) tabele DB-a.

lintosql15

Razlika izmedju dizajnera DataSeta i LINQ to SQL je ta što u ovom drugom slučaji ne specificiramo SQL upit prilikom formiranja klase odnosno entiteta tabele. U tutorijalu smo vidjeli jedan od načina mapiranja tabele, gdje nam dizajner VS preko modela generiše izvorni kod. Na sljedećoj slici prikazan model baze podataka sa klasom Customers.

lintosql16

Analizirajmo izvorni kod koji je generirao VS. Sljedeća slika pokazuje generirani izvorni kod. Primjetićemo da je VS generirao dvije klase i to:

· NorthWindKlaseDataContext

· Customers

Customers klasa je mapirana tabela Customers baze podataka, dok druga NorthWindDataContext koja klasa obavlja transakcija izmedju klijenta i servera. O DataContext klasi biće riječi kasnije.

lintosql17

Primjetićemo da iznad klase Customers se nalazi Atribut Table koji posjeduje jedan argument i to naziv tabele iz DB. Ovim atributom korespodentna klasa se označava kao klasa generirana prilikom mapiranja tabele iz DB. Ako se naziv klase podudara sa nazivom tabele u DB, kompajler je dovoljno „pametan“ da izvrši mapiranje sa tabelom i bez pomenutog atributa. Isti je slučaj i sa DataContextom.

Implementacija klase Customers je vrlo jednostavna i sastoji se od implementacije osobina (Properties) klase, koje odgovaraju kolonama tabele Customers. Naravno, imamo mogućnost da dodajemo nove osobine (Properties) samo klasi u glavno ako želimo na novou aplikacije da dodajemo dodatne kolone u vidu prekalkulisanih kolona i sl.

Klasa pored spomenutog posjeduje i nekoliko parcijalnih metoda (Partial methods o kojim sam pisao ranije) metode koje se implementiraju po potrebi. Sve osobine klase mogu se pregleavati i u dizajnerskom modulu odnosno podešavati po potrebi.

Osobine klase Customers

Atribute tabele koristimo prilikom formiranja klase (entiteta) u modelu koja korespondira tabeli u DB. Atribute možemo podešavati kako iz dizajnera tako i kroz izvorni kod. Sljedeća slika nam prikazjuje osobine klase Customers, koje većom predstavljaju atribute tebele. Možemo primjeti da postoji samo jedan atribut kojeg možemo promijeniti, a to je naziv (Name) entiteta.

clip_image036

Atribute tabele dobijamo kada desnim klikom iz kontekstnog menija izaberemo opciju Properties.

Osobine članova klase Customers

Svaka generirana klasa posjeduje osobone koje korespondiraju kolonama tabele DB. Na sljedećoj slici su prikazane osobine članova klase, koje u većem broju predstavljaju i same atribute kolona.

clip_image038

Osobine koje predstavljaju i atribute kolona prikazani su masnim fontom.

· Access – identifikator pristupa članu u klasi

· Auto Generated Value (IsDbGenerated)- indikator da se osobina klase (kolona tabele) generira i DB. Ovo uglavnom posjeduju kolone koje su primarni ključevi tabela, a imaju osobinu autogeneriranja vrijednosti. Ako je to slučaj onda pored true vrijednosti ovog atributa, atribut DBType mora imati IDENTITY() oznaku.

· Auto-Sync (AutoSync) – Određuje način sihronizacije kolone (člana klase) nakon što se izvrši upit Insert ili Update. Moguće vrijednosti su: OnInsert – sihroniziraj kada se desi Insert upit, OnUpdate – sihroniziraj kada se desi Update upit, Always – uvijek sihroniziraj vrijednost kolone, Never – nema sihronizacije.

· Delay Loaded – Određuje način učitavanja kolone iz DB prilikom privog pristupa DB. Ovu osobinu korisno je koristiti za BLOB kolone koje sadrže slike ili neke druge velike podatke u koloni. Ova osobina nam omogućava da se vrijednost kolone učitava samo u onom trenutku kada je to zaista potrebno.

· Inheritance Modifer – identifikator preklapanja člana klase.

· Name – naziv člana

· Nullable (CanBeNull) – identifikator stanja vrijednosti. Da li korespodentna kolona može sadržavati NULL vrijednost.

· Pripary Key (IsPrimaryKey) – oznaka kolone da li reprezentira primarni ključ.

· Read Only – identifikator da li član može biti promjenjen.

· Server Data Type – Tip podatka kolone koja je definisana u DB.

· Source (Storage)- Naziv varijable u kojoj se pohranjuju vrijednosti.

· Time Stamp – da li je kolona označena kao TimeStamp.

· Type (DBType)– tip podatka člana.

· UpdateCheck (UpdateCheck) – određuje način na koji LINQ to SQL definiše optimistic concurrency konflikte u DB.Moguće vrijednosti: Always– uvijek koristi kolonu za detekciju konflikta u BD, Never: nekoristi kolonu za detekciju konflikta, WhenChanged : koristi kolonu samo kad je član klase (Entiteta)promjenjen.

Primjer manipulacije tabele Customers pomoću LINQ

Kroz naredni primjer vidjećemo kako koristiti razne LINQ operatore prilikom izvlačenja informacija iz DB. Više informacija o operatorima u LINQ možete naći u pretodnom postu o LINQ. Za ovaj tutorijal slično kao u prethodnom primjeru formirajte Windows Forms C# aplikaciju, te formirajte model DB i mapirajte Tebelu Customers. U Form1 formirajte dataGridView kontrolu i povežite je sa modelom slično kao i u prethodnom slučaju.

Primjer 1. Za privi primjer pokušat ćemo izdvojiti sve partnere čije je sjedište u Londonu. Naš LINQ upit za ovaj slučaj prikazan je na sljedećoj slici.

clip_image040

Poslije pokretanja aplikacije rezulat bi trebao biti kao na sljedečoj slici:

lintosql21

Primjer 2: Potrebno je grupirati sve poslovne partner po gradovima, te u drugoj koloni prikazati broj partnera za svaki grad. LINQ upit za ovaj primjer prikazan je na sljedećoj slici:

clip_image044

Manipulacija nad Master/Detail relacijama

Kako je već kazano LINQ to SQL u potpunosti podržava relacije između tabela u DB. Čak šta više kada je definisana relacija izmedju klasa (entiteta) u dizajneru nije potrebno posebno definisanje relacija (u vidu JOIN naredbe). Ako mapiramo tabele Customers i Orders u dizajner kao na sljedećoj slici možemo primjetiti da se formirala relacija medju njima automatski.

clip_image046

To znači da je dizajner pored mapiranja tabela mapirao i relaciju madju njima jer je ona definisana u DB. Naravno, relaciju medju klasama možemo definisati i ručno. To radimo ako iz ToolBoxa povučemo stavku Asocciationclip_image048.

Ako kliknemo desnom tipkom miša na relaciju i izaberemo opciju Preperties u Property prozoru dostupne su nam osobine relacije.

clip_image050

· Cardinality – vrsta relacije

· Child Property – osobine tabele potomka

· Parent Property – osobine tabele roditelja

· Participating Property – detalji relacije medju tabelama

· Unique – jedinstvenost vanjskog ključa

Primjer manipulacije nad tabelama u Master/Detal relaciji

Koristeći prethodni primjer i dizajner kojeg smo upravo kreirali napravićemo nekoliko primjera svojstvenih ovakvoj zavisnosti medju tabelama.

Primjer 1. Izvucimo sve narudžbe kupaca iz Londona.

Za ovaj primjer LINQ upit izgleda kao na sljedećoj slici.

clip_image052

Ako prokrenemo aplikaciju rezulat dobijamo kao na sljedećoj slici.

lintosql27

Iz ovog primjera vidimo da ako želimo da izvlačimo podatke iz dvije zavisne tabele, dovoljno je da kod deklarisanja klasa definišemo relaciju izmedju njih, a LINQ upite konstruišemo bez naredbe JOIN. Ovo je jeddna od najvažnijih osobina LINQ to SQL. Klasa Order u prethodnom primjeru već ima u sebi sadržave sve kupce (Customers). Najinteresantnije je da se pogleda Log od DataContexta i vidi na koji način se SQL string prosljedio SQL Serveru. Donja slika pokazuje SQL upit koji je prosljeđen SQL Serveru baziran na našem zadnjem primjeru LINQ.

Da bi prikazali u U otput Window SQL koji se prosljedjiva SQL Serveru potrebno je komande iz DataContext – a poslati u Output preko:

clip_image056

Naravno oni koji posjeduju SQL Server mogu pokrenuti profiler i pogledati SQL upite koji dolaze.

clip_image058

Sa slike se vidi da je SQL upit koji je generiran u sebi sadrži SQL komande spajanja (JOIN). Ista situacija se dešava ako povežemo nekoliko tabela hiearhijski u Master/Detail relacije.

Nastavlja se…….