<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Beniamin Zaborski&#039;s Blog (BeniaminZaborski.com)</title>
	<atom:link href="http://beniaminzaborski.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://beniaminzaborski.wordpress.com</link>
	<description>Projektowanie, Programowanie, Codzienność</description>
	<lastBuildDate>Mon, 30 May 2011 19:02:09 +0000</lastBuildDate>
	<language>pl</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='beniaminzaborski.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Beniamin Zaborski&#039;s Blog (BeniaminZaborski.com)</title>
		<link>http://beniaminzaborski.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://beniaminzaborski.wordpress.com/osd.xml" title="Beniamin Zaborski&#039;s Blog (BeniaminZaborski.com)" />
	<atom:link rel='hub' href='http://beniaminzaborski.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Entity Framework code-first &#8211; pierwsze koty za płoty</title>
		<link>http://beniaminzaborski.wordpress.com/2011/05/30/entity-framework-code-first-pierwsze-koty-za-ploty/</link>
		<comments>http://beniaminzaborski.wordpress.com/2011/05/30/entity-framework-code-first-pierwsze-koty-za-ploty/#comments</comments>
		<pubDate>Mon, 30 May 2011 19:02:06 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[How Can I Take ...]]></category>
		<category><![CDATA[Entity Framework]]></category>
		<category><![CDATA[Entity Framework Code-First]]></category>
		<category><![CDATA[Entity Framework POCO]]></category>
		<category><![CDATA[Mapping]]></category>
		<category><![CDATA[O/R Mapper]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=184</guid>
		<description><![CDATA[W ostatnim czasie pojawiło się kilka zmian w Entity Framework obok których nie sposób przejść obojętnie. Od dawna przyglądam się rozwojowi tego O/R mappera, ale jak dotąd nigdy nie byłem jeszcze tak podekscytowany jak teraz. Co takiego wywołuje ową ekscytację? Code-first! Tak to jest to. Z pełną świadomością mogę powiedzieć, że dla mnie code-first = [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=184&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>W ostatnim czasie pojawiło się kilka zmian w Entity Framework obok których nie sposób przejść obojętnie. Od dawna przyglądam się rozwojowi tego O/R mappera, ale jak dotąd nigdy nie byłem jeszcze tak podekscytowany jak teraz. Co takiego wywołuje ową ekscytację? Code-first! Tak to jest to. Z pełną świadomością mogę powiedzieć, że dla mnie code-first = Entity Framework. Wszystko co jest poza tym w EF już może nie istnieć. Ale postarajmy się to nieco uporządkować.</p>
<p>Entity Framework dostarcza trzy różne podejścia do odwzorowywania encji modelu domeny na relacyjne obiekty bazy danych:</p>
<p>- database-first: zaczynamy od utworzenia bazy danych, a EF automatycznie generuje klasy modelu na podstawie struktury bazy danych</p>
<p>- model-first: zaczynamy od utworzenia klas modelu w dedykowanym designerze i mapujemy je na istniejącą bazę danych lub EF generuje bazę na podstawie stworzonego modelu</p>
<p>- code-first: zaczynamy od utworzenia klas modelu wprost w kodzie i mapujemy na obiekty bazy danych.</p>
<p>W dalszej części zamierzam skupić się na tym ostatnim podejściu. Według mojego może odrobinę subiektywnego odczucia jest to jedyny wartościowy sposób użycia EF. Kontrowersyjne? Otóż nie do końca. Patrząc przez pryzmat programisty używającego przez kilka lat NHibernate (ostrzegałem, że może nie być obiektywnie) takie podejście wydaje się być zupełnie naturalne.</p>
<p>Rozpoczynam od utworzenia obiektów modelu domeny &#8211; obiektów POCO rzecz jasna &#8211; nie myśląc na tym etapie o projektowaniu relacji bazy danych (Domain Driven Development). W następnej kolejności tworzę odpowiednią strukturę bazy danych i mapuję na nią klasy modelu. Entity Framework potrafi sam wygenerować strukturę bazy danych na podstawie klas modelu stosując analogiczne nazewnictwo do nazw klas i ich właściwości. Wygodne rozwiązanie, jednak życie pokazuje, że mało praktyczne szczególnie w dużych projektach. Każdy z nas ma jakieś przyzwyczajenia co do nazewnictwa obiektów w bazie danych – ja również i one się nie pokrywają z konwencjami nazewniczymi dostarczanymi przez EF. Przyzwyczajenia owszem można zmienić, co jednak gdy korporacja posiada ścisłe reguły co do nazywania obiektów w bazie danych? Głową muru się nie przebije, stąd potrzeba elastycznego mechanizmu konfiguracji mapowania. Na początku się obawiałem na jak wiele pozwoli nam tutaj Microsoft. Niepotrzebnie, bo za pomocą fluent API można naprawdę dużo. Nie jest to co prawda tak dużo jak oferuje NHibernate, ale nie powinno to wpłynąć na wygodę używania Entity Framework Code-First.</p>
<p>Korzystając z podejścia code-first mamy trzy sposoby na mapowanie obiektowo-relacyjne. Po pierwsze, wspomniane już, automatyczne generowanie struktury bazy danych; po drugie mapowanie przy pomocy atrybutów z przestrzeni nazw System.Data.Annotations; i po trzecie preferowane przeze mnie ze względu na swoje możliwości – fluent API.</p>
<p>Nie uważam, aby mapowanie przy pomocy atrybutów było złym rozwiązaniem, po prostu fluent API wydaje mi się lepsze. Dzięki temu mogę odseparować model od bazy danych i stworzyć go bardziej „czystym”. Pod tym względem zdecydowanie jestem purystą.</p>
<p>Przeanalizujmy sposób użycia fluent API na podstawie projektu prostej aplikacji konsolowej stworzonej w Visual Studio, którą można pobrać <a title="stąd" href="http://cid-df717283aff81511.office.live.com/self.aspx/Beniamin%20Zaborski%5E4s%20Blog/Biz.EFCodeFirstSampleApp.zip" target="_blank">stąd</a>. Trywialny model domeny (mocno anemiczny) posiada jedynie cztery klasy. Nie w tym rzecz jednak. Różne relacje między tymi klasami obrazują to co najważniejsze w kontekście konfiguracji mappingu. Projekt pokazuje jak zmapować relacje między obiektami typu: many-to-one (Uzytkownik-&gt;Rola), one-to-many (Uzytkownik-&gt;Komputer) czy many-to-many (Rola-&gt;Uprawnienie).</p>
<p>Przejdźmy do tworzenia wspomnianego modelu domeny, dodając do projektu cztery następujące klasy:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">class </span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Komputer</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> long</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">? Id { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Nazwa { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> AdresIP { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">class </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uprawnienie</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">long</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">? Id { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Nazwa { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">IList</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Rola</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt; Role { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">class</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Rola</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">long</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">? Id { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Nazwa { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> IList</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uprawnienie</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt; Uprawnienia { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> class</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Uzytkownik</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">long</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">? Id { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Login { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> bool</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> CzyAktywny { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Rola</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> Rola { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">IList</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Komputer</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt; Komputery { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p>Kolejnym krokiem jest wygenerowanie stosownej struktury tabel w bazie danych zgodnie z przyjętą przez siebie/organizację konwencją. Pomijam opis tego procesu, bo może być wykonany na wiele sposobów. Począwszy od „ręcznego” utworzenia tabel, aż po skorzystanie z własnych dedykowanych do tego narzędzi. Niejednokrotnie jest tak, że otrzymujemy już gotową strukturę bazy danych od programisty baz danych. W załączonym projekcie znajduje się skrypt SQL tworzący wymaganą strukturę bazy danych (dla MS SQL Server).</p>
<p>Mamy model domeny w postaci klas, mamy strukturę bazy danych – czas przejść do mapowania. Zanim jednak to zrobimy, dodajmy jeszcze connection string do naszej bazy danych do pliku konfiguracyjnego aplikacji app.config:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">connectionStrings</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p><span style="color:#0000ff;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">clear</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">/&gt;</span></span></span></p>
<p><span style="color:#0000ff;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">add</span></span></span><span style="color:#ff0000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">name</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">=</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">ConnStr</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span></p>
<p><span style="color:#ff0000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">connectionString</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">=</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Data Source=(local);Initial Catalog=EF_CODE_FIRST_SAMPLE_DB;Integrated Security=SSPI;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span></p>
<p><span style="color:#ff0000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">providerName</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">=</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">System.Data.SqlClient</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> /&gt;</span></span></span></p>
<p><span style="color:#0000ff;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;/</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">connectionStrings</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p>Kluczowym elementem aplikacji z wykorzystaniem Entity Framework code-first jest klasa DbContext z przestrzeni nazw System.Data.Entity. Pełni ona rolę wzorca Repository, a także jednocześnie Unit Of Work. To dzięki tej klasie możemy wykonywać na encjach modelu wszelkie operacie CRUD w ramach transakcji. Oznacza to, że naszym kolejnym krokiem jest utworzenie właśnie klasy dziedziczącej po DbContext. Zróbmy to:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">class</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> ModelContext</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> : </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">DbContext</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> ModelContext() : </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">() { }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> ModelContext(</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">string</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> stringNameOrConnectionString) : </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">(stringNameOrConnectionString) { }</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p>Użyłem tu przeciążenia konstruktora, które pozwoli nam podać nazwę connection stringa z pliku konfiguracyjnego lub wprost podać connection string do bazy danych.</p>
<p>Kolejna bardzo istotna klasa, funkcjonująca nierozerwalnie z DbContext, to DbSet&lt;&gt;. Reprezentuje kolekcję encji danego typu w ramach kontekstu jaki definiuje nam klasa DbContext. Dodajmy zatem stosowne kolekcje encji do klasy ModelContext:</p>
<p><span style="color:#0000ff;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">DbSet</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Rola</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt; Role { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">DbSet</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uzytkownik</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt; Uzytkownicy { </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">get</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">set</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">; }</span></span></span></p>
<p>W tym momencie możemy przejść już do samego mapowania z użyciem fluent API. W związku z tym w klasie ModelContext musimy przesłonić metodę OnModelCreating:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">protected </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">override </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">void</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> OnModelCreating(</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">DbModelBuilder</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> modelBuilder)</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.OnModelCreating(modelBuilder);</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p>To jest właśnie to miejsce w którym definiujemy konfigurację mappingu. Możemy to zrobić wprost w tej metodzie lub lepszym pomysłem będzie wydzielenie mappingu poszczególnych encji do dedykowanych klas. Sprawdza się to szczególnie w większych projektach. W tym celu należy utworzyć klasę dziedziczącą po EntityTypeConfiguration&lt;&gt; dla każdej encji:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> class </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">KomputerMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> : </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">EntityTypeConfiguration</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Komputer</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> KomputerMapping()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">: </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasKey(e =&gt; e.Id).Property(e =&gt; e.Id).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_KOMPUTERA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.Nazwa).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;NAZWA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.AdresIP).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ADRES_IP&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;KOMPUTERY&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">class</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> UprawnienieMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> : </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">EntityTypeConfiguration</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uprawnienie</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> UprawnienieMapping()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">: </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasKey(e =&gt; e.Id).Property(e =&gt; e.Id).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UPRAWNIENIA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.Nazwa).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;NAZWA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;UPRAWNIENIA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> class </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">RolaMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> : </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">EntityTypeConfiguration</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Rola</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> RolaMapping()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">: </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasKey(e =&gt; e.Id).Property(e =&gt; e.Id).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.Nazwa).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;NAZWA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasMany&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uprawnienie</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;(u =&gt; u.Uprawnienia).WithMany(u =&gt; u.Role).Map(</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">m =&gt; m.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;UPRAWNIENIA_DLA_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">.MapLeftKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">.MapRightKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UPRAWNIENIA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ROLE&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> class </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">UzytkownikMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> : </span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">EntityTypeConfiguration</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uzytkownik</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">public</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;"> UzytkownikMapping()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">: </span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">base</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">()</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">{</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasKey(e =&gt; e.Id).Property(e =&gt; e.Id).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UZYTKOWNIKA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.Login).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;LOGIN&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.Property(e =&gt; e.CzyAktywny).HasColumnName(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;CZY_AKTYWNY&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasRequired(e =&gt; e.Rola).WithMany().Map(p=&gt;p.MapKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">));</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasMany(e =&gt; e.Komputery).WithOptional().Map(p =&gt; p.MapKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UZYTKOWNIKA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)).WillCascadeOnDelete();</span></span></span></p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;UZYTKOWNICY&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">}</span></span></span></p>
<p>To jest kompletny mapping dla naszego modelu domeny. Przyjrzyjmy się kluczowym elementom. Wywołanie HasKey() wskazuje które property jest primary key w naszej encji, natomiast Property() umożliwia zmapowanie konkretnej właściwości na konkretną kolumnę w tabeli bazy danych. Użyłem wywołania HasColumnName(), aby wskazać inną nazwę kolumny w tabeli – nieodpowiadającą konwencji nazewniczej EF. To wszystko okraszone jest wywołaniem ToTable(), gdzie wskazujemy nazwę tabeli odpowiadającą encji. Mapowanie klucza głównego i właściwości typów prostych wygląda na niezbyt skomplikowane. Czas przejść do mapowania relacji między obiektami.</p>
<p>Na pierwszy ogień many-to-one czyli zwykła referencja do innego typu encji z naszego modelu. Dobrym przykładem jest powiązanie użytkownika z rolą. Klasa Uzytkownik posiada referencję do klasy Rola, przy czym jest to referencja wymagana. Mapujemy to za pomocą wywołania HasRequired() wskazując nazwę właściwości przechowującej referencję do klasy Rola. W związku z tym, że także w tym wypadku konwencja nazewnicza klucza obcego w tabeli nie odpowiada tej z EF należy wskazać nazwę. Robimy to przy pomocy wywołania MapKey() podając nazwę klucza obcego w tabeli. Kompletny przykład mapowania takiej relacji wygląda następująco:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasRequired(e =&gt; e.Rola).WithMany().Map(p=&gt;p.MapKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">));</span></span></span></p>
<p>W sytuacji kiedy property przechowujące referencję nie jest wymagane, to zamiast HasRequired() użyjemy HasOptional().</p>
<p>Innym typem relacji jest kolekcja czyli one-to-many. Przeanalizujmy to na przykładzie kolekcji elementów Komputer w klasie Uzytkownik. Do zmapowania listy używamy wywołania HasMany() podając jako parametr property &#8211; za pomocą wyrażenia lambda oczywiście – które wskazuje naszą kolekcję. W związku z tym, iż ta właściwość nie jest wymagana używamy WithOptional(). Jak się wszyscy domyślają w przeciwnym wypadku użylibyśmy WithRequired(). Wywołanie Map() z MapKey() wygląda już znajomo i używamy go by wskazać klucz obcy w tabeli zawierającej rekordy będące elementami listy. Dodatkowo na końcu znajduje się wywołanie metody WillCascadeOnDelete(). Cóż to takiego? Nic innego jak wskazanie czy podczas usunięcia elementu nadrzędnego ma być wywołane kaskadowe usunięcie elementów podrzędnych, czyli tych w naszej kolekcji. Cały przykład wygląda następująco:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasMany(e =&gt; e.Komputery).WithOptional().Map(p =&gt; p.MapKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UZYTKOWNIKA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)).WillCascadeOnDelete();</span></span></span></p>
<p>Na koniec najbardziej skomplikowana relacja czyli many-to-many. Przykładem takiego powiązania jest wzajemna relacja między obiektami Rola i Uprawnienie. Rola posiada kolekcję elementów Uprawnienie i vice versa, tj. Uprawnienie posiada kolekcję elementów Rola. Aby zmapować takie powiązanie na postać relacyjną potrzebujemy dodatkowej tabeli. Ta tabela przechowuje pary identyfikatorów roli i uprawnienia. Dobrze, aby kluczem głównym takiej tabeli była owa para identyfikatorów. Mapowania wykonujemy z jednej ze stron np. z encji Rola. Spójrzmy na przykład:</p>
<p><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">this</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">.HasMany&lt;</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">Uprawnienie</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&gt;(u =&gt; u.Uprawnienia).WithMany(u =&gt; u.Role).Map(</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">m =&gt; m.ToTable(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;UPRAWNIENIA_DLA_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">.MapLeftKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_ROLI&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">.MapRightKey(</span></span></span><span style="color:#a31515;"><span style="font-family:Consolas;"><span style="font-size:x-small;">&#8222;ID_UPRAWNIENIA&#8221;</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">)</span></span></span></p>
<p><span style="color:#000000;"> <span style="font-family:Consolas;"><span style="font-size:x-small;">);</span></span></span></p>
<p>Wywołujemy generyczną wersję metody HasMany, podając jako parametr generyczny typ elementu kolekcji, a jako parametr wywołania właściwość klasy przechowującą kolekcję tych elementów. Następnie w wywołaniu WithMany podajemy wskazanie w drugą stronę tj. w tym przypadku na kolekcję elementów Rola. Ostatni element mapowania relacji wiele do wielu i najważniejszy to wskazanie wspomnianej tabeli powiązania w Map(). Nazwę tabeli podajemy w wywołaniu ToTable i wskazujemy nazwy kolumn kluczy obcych do obu typów encji/tabel. Należy dodać, że left key to klucz obcy wskazujący na typ którego mapping opisujemy, a right key to klucz obcy wskazujący na typ elementów kolekcji.</p>
<p>Tak by wyglądał przyznaje, że dość pobieżny opis mapowania encji w moim prostym projekcie. Uważam, że fluent API jest na tyle intuicyjne i samo-opisujące iż czysty kod wielu z Was najlepiej pomoże uchwycić to wszystko.</p>
<p>Ostatnim krokiem jest wskazanie, które z klas „konfiguracyjnych” definiują mapping których encji. To bardzo proste &#8211; w metodzie OnModelCreating dodajemy:</p>
<p><span style="font-family:Consolas;"><span style="font-size:x-small;">modelBuilder.Configurations.Add(</span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">new</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">RolaMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">());</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">modelBuilder.Configurations.Add(</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">new</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">UzytkownikMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">());</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">modelBuilder.Configurations.Add(</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">new</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">KomputerMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">());</span></span></span></p>
<p><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">modelBuilder.Configurations.Add(</span></span></span><span style="color:#0000ff;"><span style="font-family:Consolas;"><span style="font-size:x-small;">new</span></span></span><span style="color:#2b91af;"><span style="font-family:Consolas;"><span style="font-size:x-small;">UprawnienieMapping</span></span></span><span style="color:#000000;"><span style="font-family:Consolas;"><span style="font-size:x-small;">());</span></span></span></p>
<p>Zachęcam jeszcze do przeanalizowania kompletnego projektu zamieszczonego <a title="tutaj" href="http://cid-df717283aff81511.office.live.com/self.aspx/Beniamin%20Zaborski%5E4s%20Blog/Biz.EFCodeFirstSampleApp.zip" target="_blank">tutaj</a>.</p>
<p>Na koniec nie mógłbym nie podkreślić tego, iż trzymam kciuki za dalszy rozwój Entity Framework właśnie w tym kierunku – jedynym słusznym kierunku.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/184/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/184/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/184/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=184&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2011/05/30/entity-framework-code-first-pierwsze-koty-za-ploty/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Prośby zostały wysłuchane, czyli POCO w Entity Framework.</title>
		<link>http://beniaminzaborski.wordpress.com/2010/06/23/prosby-zostaly-wysluchane-czyli-poco-w-entity-framework/</link>
		<comments>http://beniaminzaborski.wordpress.com/2010/06/23/prosby-zostaly-wysluchane-czyli-poco-w-entity-framework/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 21:43:31 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Codzienne dylematy modelarza]]></category>
		<category><![CDATA[Entity Framework POCO]]></category>
		<category><![CDATA[O/R Mapper]]></category>
		<category><![CDATA[Persistence Ignorant]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=169</guid>
		<description><![CDATA[Jakiś czas temu pisałem na blogu czemu nie lubię Entity Framework, narzekałem i wytykałem błędy (zresztą nie byłem w tym sam). W tym momencie muszę przyznać, że Microsoft stanął na wysokości zadania i &#8222;naprawił&#8221; to co mnie najbardziej irytowało w Entity Framework. Tak &#8211; teraz encje są obiektami POCO, a sam Entity Framework ma cechy [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=169&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Jakiś czas temu pisałem na <a title="blogu" href="http://beniaminzaborski.wordpress.com/2010/03/20/dlaczego-nhibernate-jest-wciaz-moim-ulubionym-or-mapperem/" target="_blank">blogu</a> czemu nie lubię Entity Framework,  narzekałem i wytykałem błędy (zresztą nie byłem w tym sam). W tym  momencie muszę przyznać, że Microsoft stanął na wysokości zadania i  &#8222;naprawił&#8221; to co mnie najbardziej irytowało w Entity Framework. Tak &#8211;  teraz encje są obiektami POCO, a sam Entity Framework ma cechy O/R  Mappera w stylu persistence ignorant. Wszystko jest w najlepszym  porządku. Dla tych, którzy nie widzą problemu w używaniu O/R Mappera,  który nie jest persistence ignorant mam dobrą wiadomość, bo nadal EF  może działać po &#8222;staremu&#8221; i domyślnie tak działa.</p>
<p>Aby jednak móc  skorzystać z tego cudu jakim jest persistence ignorant w EF, w Visual  Studio należy doinstalować odpowiedni generator. Ta operacja w Visual  Studio 2010 jest dziecinnie prosta, gdyż wystarczy po utworzeniu modelu  EF z menu kontekstowego designera encji wybrać &#8222;Add Code Generation  Item&#8230;&#8221; -&gt; Online Templates -&gt; Templates -&gt; Database -&gt;  &#8222;ADO.NET C# POCO Entity Generator&#8221;. Po zainstalowaniu dodatku zobaczymy w  naszym solution pliki szablonów *.tt oraz związany z nimi custom tool  TextTemplatingFileGenerator.</p>
<p>Dzięki szablonom i generatorowi  możemy się cieszyć encjami POCO w EF. Obiekty encji teraz to czyste  obiekty, które nie dziedziczą już ze specyficznej klasy bazowej jak to w  &#8222;starym&#8221; EF było. Dodać należy jeszcze tylko tyle, że działa tu lazy  loading oraz change tracking.</p>
<p>Jest dobrze, ale czy nie może być  lepiej? Zawsze może! W związku z tym zawsze można wprowadzić modyfikacje  do szablonów generatora, aby przystosować generowany kod jeszcze  bardziej do własnych potrzeb. Zachęcam do zapoznania się z POCO Entity  Generator dla Entity Framework. Hmm &#8230; może to właśnie EF kiedyś  zastąpi NH w moich projektach (?).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/169/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/169/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/169/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=169&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2010/06/23/prosby-zostaly-wysluchane-czyli-poco-w-entity-framework/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Dlaczego NHibernate jest wciąż moim ulubionym O/R Mapperem?</title>
		<link>http://beniaminzaborski.wordpress.com/2010/03/20/dlaczego-nhibernate-jest-wciaz-moim-ulubionym-or-mapperem/</link>
		<comments>http://beniaminzaborski.wordpress.com/2010/03/20/dlaczego-nhibernate-jest-wciaz-moim-ulubionym-or-mapperem/#comments</comments>
		<pubDate>Sat, 20 Mar 2010 09:54:40 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Codzienne dylematy modelarza]]></category>
		<category><![CDATA[Entity Framework]]></category>
		<category><![CDATA[NHibernate]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=164</guid>
		<description><![CDATA[W zasadzie pytanie powinno brzmieć: dlaczego Entity Framework szybko nie stanie się moim ulubionym O/R Mapperem? Po kilkuletniej przygodzie z NHibernate postanowiłem, jakiś czas temu, sprawdzić jak się ma konkurencja. Po szumnych zapowiedziach Microsoftu o inwestowaniu ogromnych sił i środków w rozwój ich flagowego, jak się okazuje, O/R Mappera sięgnąłem po Entity Framework. Coś musi [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=164&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><!-- 		@page { size: 21cm 29.7cm; margin: 2cm } 		P { margin-bottom: 0.21cm } -->W zasadzie pytanie powinno brzmieć: dlaczego Entity Framework szybko nie stanie się moim ulubionym O/R Mapperem? Po kilkuletniej przygodzie z NHibernate postanowiłem, jakiś czas temu, sprawdzić jak się ma konkurencja. Po szumnych zapowiedziach Microsoftu o inwestowaniu ogromnych sił i środków w rozwój ich flagowego, jak się okazuje, O/R Mappera sięgnąłem po Entity Framework. Coś musi być na rzeczy bo w „branży” dwie litery EF stały się mocno popularne – wręcz trendy. Zachęcony tym całym szumem wokół tej technologii, a także mając w pamięci prelekcję Julii Lerman z C2C&#8217;09 stworzyłem swój pierwszy projekt w EF. Hmm … ładny designer encji;). Tu się wszystko skończyło – dawno nie byłem tak rozczarowany! Dwie kwestie rozłożyły wszystko:</p>
<ul>
<li>obiekty domeny nie są POCO</li>
<li>O/R mapper nie jest „Persistence 	Ignorance”</li>
</ul>
<p>Obie te dwie cechy mają ze sobą wiele wspólnego. Przede wszystkim mój kod z użyciem EF posiada zbyt wiele zależności do konkretnych technologii łamiąc zasady architektury aplikacji biznesowych jak i wielu wzorców projektowych. Oczywistym mogło by się wydawać to, iż O/R Mapper nie powinien wymagać dziedziczenia encji po własnych klasach. Tak samo oczywiste jest to, że domena aplikacji nie powinna mieć świadomości o mechanizmie zapisu/pobierania danych. A jednak! Bez sarkazmu i zupełnie szczerze mówiąc, nie rozumiem tak wielkiej ignorancji twórców EF. Przyglądam się i nadal kibicuję EF mając nadzieję, że kolejne wersje przyniosą znaczące zmiany w tych dwóch kwestiach. Tymczasem zostaję przy sprawdzonym NHibernate.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/164/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/164/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/164/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=164&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2010/03/20/dlaczego-nhibernate-jest-wciaz-moim-ulubionym-or-mapperem/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Error Provider</title>
		<link>http://beniaminzaborski.wordpress.com/2009/11/30/error-provider/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/11/30/error-provider/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 18:21:56 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[How Can I Take ...]]></category>
		<category><![CDATA[ErrorProvider]]></category>
		<category><![CDATA[IDataErrorInfo]]></category>
		<category><![CDATA[Validation]]></category>
		<category><![CDATA[Window Forms]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=154</guid>
		<description><![CDATA[W poniższym artykule chciałbym poruszyć kwestię związana z walidacją obiektów. Oczywiste jest, że walidacja jest niezbędnym elementem każdej dobrze zaprojektowanej aplikacji biznesowej. Jednak nie sam sposób walidowania obiektów jest przewodnim tematem tego artykułu. Chciałbym przedstawić pewien dość oczywisty sposób informowania użytkownika o błędach. Do napisania tego artykułu zainspirowało mnie pytanie mojego znajomego &#8230; właśnie na [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=154&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>W poniższym artykule chciałbym poruszyć kwestię związana z walidacją obiektów. Oczywiste jest, że walidacja jest niezbędnym elementem każdej dobrze zaprojektowanej aplikacji biznesowej. Jednak nie sam sposób walidowania obiektów jest przewodnim tematem tego artykułu. Chciałbym przedstawić pewien dość oczywisty sposób informowania użytkownika o błędach. Do napisania tego artykułu zainspirowało mnie pytanie mojego znajomego &#8230; właśnie na podobny temat. Okazuje się, że nie wszystko jest tak oczywiste jak sądzimy. Na wstępie chciałbym zaznaczyć, iż artykuł dotyczy aplikacji Window Forms.<br />
Większość z nas pewnie widziała w aplikacjach ASP.NET ikonki przy polach edycyjnych informujące o wymagalności danego pola lub zbyt dużej ilość znaków – ogólnie o niespełnionych regułach walidacyjnych. Podobny efekt możemy uzyskać w aplikacjach Window Forms. Tu kolejna dobra wiadomość &#8211; za pomocą standardowych kontrolek i to w łatwy sposób. Odpowiedzialna za to jest kontrolka o nazwie <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.errorprovider.aspx">ErrorProvider</a>. Poniższy zrzut ekranu przedstawia wspomnianą kontrolkę w akcji.</p>
<p><img src="http://beniaminzaborski.files.wordpress.com/2009/11/errorproviderscreen.jpg" alt="" /></p>
<p>Niespełniona reguła walidacyjna na wskazanym property obiektu powoduje wyświetlenie ikony przy odpowiedniej kontrolce. Szczegóły niespełnionych reguł są wyświetlane w tooltipie. Wiemy zatem co chcemy uzyskać, teraz pytanie jak?</p>
<p>Zacznę może od samego obiektu który podlega walidacji. W aplikacjach biznesowych jest to z reguły jakiś DataTransferObject. Kontrolka ErrorProvider potrzebuje, aby dostarczyć do niej informacji o niespełnionych regułach walidacyjnych. Ta informacja to zwykły string czyli komunikat który ma się wyświetlić użytkownikowi. Odpowiedzialny za to jest interfejs <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.idataerrorinfo.aspx">IDataErrorInfo</a>.</p>
<p>Interfejs jest dość prosty bo posiada tylko dwie właściwości:</p>
<ul>
<li>string Error { get; }</li>
<li>string Item[string columnName] { get; }</li>
</ul>
<p>Jak się okazuje dalej implementacja tego interfejsu w naszej klasie DataTransferObject również nie jest trudna. Zakładam, że nasz DataTransferObject posiada już sam mechanizm walidowania np. wykorzystujący całkiem poręczny Application Validation Block pochodzący z Enterprise Library. Nie pozostaje teraz nic innego jak zaimplementować IDataErrorInfo w naszej klasie DataTransferObject.</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top">
public abstract class DataTransferObject : IDataTransferObject, IValidatable, IDataErrorInfo<br />
{<br />
// pominięta część kodu klasy nieistotna w omawianym kontekście<br />
string IDataErrorInfo.Error<br />
{<br />
get<br />
{<br />
if (!IsValid)<br />
return BrokenValidationRules.GetDescriptionBrokenRules();<br />
else<br />
return String.Empty;<br />
}<br />
}</p>
<p>string IDataErrorInfo.this[string columnName]<br />
{<br />
get<br />
{<br />
string result = string.Empty;<br />
if (!IsValid)<br />
{<br />
IBrokenValidationRule brokenRule = BrokenValidationRules.GetBrokenRule(columnName);<br />
if (brokenRule != null)<br />
result = brokenRule.Description;<br />
}<br />
return result;<br />
}<br />
}<br />
}</p>
</td>
</tr>
</tbody>
</table>
<p>Właściwość Error zwraca nam listę komunikatów o niespełnionych regułach na wskazanym obiekcie. Indekser zwraca nam natomiast listę komunikatów niespełnionych reguł dla wskazanej właściwości obiektu. Parametr columnName określa nazwę właściwości obiektu.</p>
<p>Przedstawiona klasa nie posiada pełnej implementacji, a jedynie te elementy które są istotne w omawianym kontekście. Oczywiste jest, że klasa musi mieć w tym wypadku kolekcję niespełnionych reguł walidacyjnych, która jest odpowiednio uzupełniana podczas wywołania walidacji. Na tej kolekcji zresztą bazują zaimplementowane właściwości z interfejsu IDataErrorInfo. W ten sposób chciałem pokazać, iż sam mechanizm walidacji jest zupełnie niezależny od implementacji IDataErrorInfo i po wprowadzeniu kilku własnych interfejsów może być łatwo wymieniany na inny.</p>
<p>Teraz możemy zająć się już interfejsem użytkownika. Pierwsze co należy zrobić to położyć na widoku kontrolkę ErrorProvider, np. przeciągając z toolboxa. Kolejnym krokiem jest zbindowanie naszego obiektu (dziedziczącego z DataTransferObject) z kontrolkami i przypisanie tego obiektu jako źródła danych do właściwości DataSource kontrolki ErrorProvider. Jeśli dodajemy kontrolkę ErrorProvider nie poprzez designera warto pamiętać o ustawieniu właściwości ContainerControl na odpowiednią formę/kontrolkę.</p>
<p>Sama kontrolka ErrorProvider posiada jeszcze kilka ciekawych właściwości jak: BlinkRate (częstotliwość pulsowania), BlinkStyle (kiedy ma pulsować ikonka) oraz Icon.</p>
<p>Powodzenia w implementacji wizualizacji wyników walidacji we własnej aplikacji w ten jakże prosty sposób.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/154/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/154/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/154/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=154&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/11/30/error-provider/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>

		<media:content url="http://beniaminzaborski.files.wordpress.com/2009/11/errorproviderscreen.jpg" medium="image" />
	</item>
		<item>
		<title>O2O Mapping</title>
		<link>http://beniaminzaborski.wordpress.com/2009/11/16/o2o-mapping/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/11/16/o2o-mapping/#comments</comments>
		<pubDate>Mon, 16 Nov 2009 22:16:46 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[How Can I Take ...]]></category>
		<category><![CDATA[Domain Entity]]></category>
		<category><![CDATA[DTO]]></category>
		<category><![CDATA[Mapping]]></category>
		<category><![CDATA[Object To Object Mapping]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=142</guid>
		<description><![CDATA[Zainspirowany jednym z postów na blogu Macieja Aniserowicza, postanowiłem bliżej przyjrzeć się zagadnieniu mapowania object-to-object. Wydaje się to być idealny lek na „głupie” mapowanie property poprzez przepisywanie każdego po kolei. A i owszem jest. Szczególnie przydatne przy mapowaniu obiektów domeny do obiektów DTO. Nie wiem ilu z Was robi/robiło to właśnie w ten tzw. „głupi” [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=142&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Zainspirowany jednym z postów na blogu <a href="http://www.maciejaniserowicz.com/post/2009/11/04/Co-to-jest-AutoMapper-i-dlaczego-warto-go-znac.aspx">Macieja Aniserowicza</a>, postanowiłem bliżej przyjrzeć się zagadnieniu mapowania object-to-object. Wydaje się to być idealny lek na „głupie” mapowanie property poprzez przepisywanie każdego po kolei. A i owszem jest. Szczególnie przydatne przy mapowaniu obiektów domeny do obiektów DTO. Nie wiem ilu z Was robi/robiło to właśnie w ten tzw. „głupi” sposób, ale ja muszę przyznać że … mhm. Przykre, jak czasem nie zauważamy tak prostych rozwiązań pozwalających zaoszczędzić sporo czasu i zbędnych linii kodu. AutoMapper bo to o nim właściwie pisał Maciej to porządne narzędzie, które powinno zainteresować każdego programistę .NET. Na pierwszy rzut oka wygląda zachwycająco, ale to chyba bardziej idea tego typu mapowania jest bardziej zachwycająca niż sam w sobie produkt. Narzekam? Nie w sumie to nie. AutoMapper jest ok, ale niektóre rozwiązania w nim mnie nie odpowiadały. Sprawdziłem inne narzędzia tego typu jak choćby Glue i … ja potrzebowałem czegoś naprawdę trywialnego, bo sama idea jest trywialna. Długo nie myśląc stwierdziłem, że te kilka klas to napisze sam w taki sposób, aby mnie odpowiadały w 100%. I stało się &#8211; od pomysłu, po implementację. Czego potrzebowałem? Niczego więcej jak mapowania ad-hoc z możliwością zdefiniowania własnych reguł ustawiania wartości właściwości w obiekcie docelowym.<br />
Oto przykład mówiący wszystko za siebie:</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top">
<span style="font-family:Courier New;"><br />
User user = new User();<br />
user.Id = Guid.NewGuid();<br />
user.Login = &#8222;Jan&#8221;;<br />
user.Password = &#8222;Secret&#8221;;<br />
user.FirstName = &#8222;Jan&#8221;;<br />
user.LastName = &#8222;Kowalski&#8221;;<br />
user.RoleName = &#8222;Admins&#8221;;</p>
<p>var mapper = new ObjectMapper&lt;User, UserDTO&gt;();<br />
mapper<br />
&nbsp;&nbsp;.AddRule(&#8222;FullName&#8221;, s =&gt; s.FirstName + &#8221; &#8221; + s.LastName)<br />
&nbsp;&nbsp;.AddRule(&#8222;Login&#8221;, s =&gt; s.Login)<br />
&nbsp;&nbsp;.AddRule(&#8222;Password&#8221;, s=&gt;SecurityUtils.Md5(s.Password));<br />
mapper.Ignore(&#8222;RoleName&#8221;);<br />
UserDTO userDTO = mapper.Map(user);<br />
</span></td>
</tr>
</tbody>
</table>
<p>Kod źródłowy do wglądu zamieszczam <a href="http://cid-df717283aff81511.skydrive.live.com/embedicon.aspx/Beniamin%20Zaborski^4s%20Blog/Biz.ObjectMapper.zip">tutaj</a>. Tak na marginesie cały pomysł jak i jego implementacja powstała podczas jednego z programów rozrywkowych z tępym żartem granego w pewnej stacji na trzy litery w poniedziałkowe wieczory. A więc jak sądzę wszystko to trwało nie więcej jak 60 minut (z reklamami) – tłumaczę się na zaś jakby jednak coś nie działało;).</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/142/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/142/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/142/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=142&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/11/16/o2o-mapping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Spring.NET vs WCF</title>
		<link>http://beniaminzaborski.wordpress.com/2009/10/13/spring-net-vs-wcf/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/10/13/spring-net-vs-wcf/#comments</comments>
		<pubDate>Tue, 13 Oct 2009 21:34:27 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[How Can I Take ...]]></category>
		<category><![CDATA[Services]]></category>
		<category><![CDATA[SOA]]></category>
		<category><![CDATA[Spring.NET]]></category>
		<category><![CDATA[WCF]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=118</guid>
		<description><![CDATA[Tytuł artykułu zdradza nieco temat jaki chciałbym podjąć. Może samo versus jest nieco przewrotne, gdyż bardziej odpowiednie byłoby &#8222;Spring.NET a WCF&#8221; czy też po prostu &#8222;Spring.NET i WCF&#8221;. Tak naprawdę to tytuł powinien brzmieć &#8222;Spring.NET a WCF versus programista&#8221; ;). Obserwując programistów zaczynających przygodę ze Spring.NET i próbujących zintegrować z tym frameworkiem technologię WCF właśnie [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=118&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Tytuł artykułu zdradza nieco temat jaki chciałbym podjąć. Może samo versus jest nieco przewrotne, gdyż bardziej odpowiednie byłoby &#8222;Spring.NET a WCF&#8221; czy też po prostu &#8222;Spring.NET i WCF&#8221;. Tak naprawdę to tytuł powinien brzmieć &#8222;Spring.NET a WCF versus programista&#8221; ;). Obserwując programistów zaczynających przygodę ze Spring.NET i próbujących zintegrować z tym frameworkiem technologię WCF właśnie taki tytuł się nasuwa. Wielu programistów napotyka na problemy przy integracji tych rozwiązań. Zatem, moim zadaniem będzie zaprezentowanie prostej aplikacji pozwalającej hostować serwisy po technologii WCF w oparciu o  Spring.NET. <br />
W jednym z moich artykułów z serii &#8222;Ugryźć Spring.NET&#8221; poświęconych <a href="http://beniaminzaborski.wordpress.com/2009/07/29/ugryzc-spring-net-%e2%80%93-cz-6-serwisy/">serwisom</a> (cz.6) napisałem, że zmiana technologii hostowania serwisów wymagać będzie jedynie zmian w konfiguracji. W dużej mierze jest to oczywiście prawda. Jednak są pewne niuanse, które wymagają wyjaśnienia. W przykładzie w tamtym artykule serwisy były hostowane za pomocą .NET Remotingu, tu będzie to WCF.<br />
A teraz uwaga skierowana w stronę wszystkich tutoriali do WCF jakie widziałem. Uważam, że wszystkie te tutoriale uczą skrajnie niepraktycznego podejścia do jednej z kwestii &#8211; client proxy. Chodzi tu o generowanie klas proxy klienta za pomocą bądź to bezpośrednio środowiska Visual Studio, bądź narzędzia svcutil.exe. Jak dla mnie wiąże się z tym podstawowa niedogodność, iż w trakcie tworzenia aplikacji mój serwis musi być już hostowany, abym mógł skorzystać z dobrodziejstw narzędzia svcutil.exe. Poza tym każda zmiana w serwisie wymaga ponownego przegenerowania. Koszmar!!! Wady takiego rozwiązania można by jeszcze mnożyć &#8211; serwisy są &#8222;mało abstrakcyjne&#8221; czyli zbyt powiązane z implementacją opartą na WCF. <br />
Proste podejście do którego się już przyzwyczaiłem to osobne assembly z interfejsem modelu aplikacji i osobne assembly z implementacją tego modelu (czytaj serwisów). <br />
Dlaczego taki model, uważany nie tylko przeze mnie za właściwy, ma być zburzony przez WCF? Ależ wcale nie musi! Gdyby tylko w tych tutorialach więcej pisano o klasie ChannelFactory i metodzie CreateChannel &#8230;<br /> Z tego rozwiązania korzysta właśnie Spring.NET. Dzięki temu migrując serwisy naszej aplikacji z .NET Remotnigu do WCF nie burzymy naszej aplikacji, a jedynie dokonujemy zmian w konfiguracji. Pozostaje tu oczywiście jedna kwestia do wyjaśnienia, czyli atrybutów WCF-a, tj. ServiceContract oraz OperationContract. One niestety muszą być użyte, więc to będzie cała zmiana w kodzie aplikacji &#8211; reszta to config. Nasze obiekty DTO są zapewne już opatrzone atrybutem Serializable i wcale nie musimy tego zmieniać na DataContract.<br />
Wyjaśniłem chyba już trochę, a zatem czas na przykład. Przykład jest trywialny. <br />
Solution składa się z czterech projektów:</p>
<ul>
<li>interfejs modelu (BeezDev.SpringWCFApplication.Model.Interface)</li>
<li>implementacja modelu (BeezDev.SpringWCFApplication.Model)</li>
<li>konsolowa aplikacja hostująca serwisy aka server (BeezDev.SpringWCFApplication.Server)</li>
<li>okienkowa aplikacja klient (BeezDev.SpringWCFApplication.Client)</li>
</ul>
<p>Aplikacja posiada jeden serwis HelloService z jedną metodą SayHello przyjmującą jako parametr jeden obiekt DTO i zwracającą inny typ obiektu DTO. Jakże wyszukana logika mówi: &#8222;podaj mi swój login, a zostaniesz przywitany&#8221;. Aplikacja serwera posiada referencję do interfejsu modelu jak i jego implementacji, natomiast już klient posiada tylko referencję do interfejsu modelu.<br />
Przyjrzyjmy się najpierw konfiguracji serwera. Nie będę oczywiście omawiał całości konfiguracji Spring.NET, a jedynie te elementy które są istotne w kontekście WCF. Pierwsza sprawa to definicja serwisu w kontenerze IoC Springa.<br />
Generalnie przy migracji z .NET Remoting ona istnieje. Jedyna zmiana, której ewentualnie musimy dokonać, to oznaczyć serwis aby nie był uruchamiany jako singleton (singleton=&#8221;false&#8221;). Jak podaje dokumentacja Spring.NET ten typ aktywacji obiektu nie współpracuje poprawnie z technologią WCF. Przyjmijmy to jako pewnik i na tym etapie nie wnikajmy w szczegóły.<br />
Cała moc Springa drzemie w eksporterach serwisów, a więc należy zdefiniować odpowiedni dla WCF:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;helloServiceHost&#8221; type=&#8221;Spring.ServiceModel.ServiceExporter, Spring.Services&#8221;&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;TargetName&#8221; value=&#8221;helloService&#8221; /&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>Nie ma tu nic nowego, poza szczególnym typem eksportera serwisu Spring.ServiceModel.ServiceExporter.<br />
Od serwera wymaga się hostowania naszego serwisu i do tego służy klasa ServiceHost. To kolejna zmiana w kodzie jaką musimy wykonać w stosunku do .NET Remoting. Zakładając, że aplikacja hostująca nie jest częścią modelu aplikacji, a więc ta zmiana się nie liczy;).<br />
Teraz klient czyli to najciekawsze z punktu widzenia WCF. Zmiany w kodzie? Nie! Żadnych zmian! Aplikacja działa tak samo, tj. pobiera instancję serwisu z kontenera IoC Spring-a i wywołuje jego metody. Zatem wszystkie zmiany ograniczą się do pliku konfiguracyjnego.<br />
Definiujemy ChannelFactory dla naszego serwisu:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;helloServiceChannelFactory&#8221; type=&#8221;System.ServiceModel.ChannelFactory&amp;lt;BeezDev.SpringWCFApplication.Model.IHelloService&gt;, System.ServiceModel&#8221;&gt;<br />
&nbsp;&nbsp;&lt;constructor-arg name=&#8221;endpointConfigurationName&#8221; value=&#8221;tcpEndpoint&#8221; /&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>Jako parametr generyczny podajemy typ naszego serwisu i kolejna rzecz wymagająca wyjaśnienia to argument konstruktora. Tutaj przekazujemy nazwę endpointa-a z konfiguracji WCF-a. O tym jeszcze wspomnę później.<br />
<br />
Następnie definicja naszego serwisu:<br />
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;helloService&#8221; type=&#8221;BeezDev.SpringWCFApplication.Model.IHelloService, BeezDev.SpringWCFApplication.Model.Interface&#8221;<br />
&nbsp;&nbsp;factory-object=&#8221;helloServiceChannelFactory&#8221;<br />
&nbsp;&nbsp;factory-method=&#8221;CreateChannel&#8221; /&gt;<br />
</span></div>
<p>Jako klasę fabrykującą wskazujemy obiekt zdefiniowany wcześniej, a metoda fabrykująca to oczywiście CreateChannel.<br />
To wszystko! No prawie wszystko;). Pozostaje kwestia konfiguracji samego WCF, która jest niejako poza tematem tego artykułu. Wspomnę tylko, że konfiguracji dokonujemy w tradycyjny sposób, tj. w sekcji system.serviceModel pliku app.config. W przykładzie użyłem hostowania serwisów po protokole TCP z binarną serializacją. Po szczegóły związane z cała magią konfiguracji WCF-a tzw. ABC odsyłam do dokumentacji.</p>
<p>Pełne solution <a href="http://cid-df717283aff81511.skydrive.live.com/self.aspx/Beniamin%20Zaborski^4s%20Blog/BeezDev.SpringWCFApplication.zip">tutaj</a>. Miłej zabawy!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/118/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/118/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/118/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=118&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/10/13/spring-net-vs-wcf/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Ugryźć Spring.NET – (cz.7) Testy jednostkowe</title>
		<link>http://beniaminzaborski.wordpress.com/2009/08/06/ugryzc-spring-net-%e2%80%93-cz-7-testy-jednostkowe/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/08/06/ugryzc-spring-net-%e2%80%93-cz-7-testy-jednostkowe/#comments</comments>
		<pubDate>Thu, 06 Aug 2009 20:20:44 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Ugryźć Spring.Net]]></category>
		<category><![CDATA[MbUnit]]></category>
		<category><![CDATA[NUnit]]></category>
		<category><![CDATA[Tests]]></category>
		<category><![CDATA[Testy jednostkowe]]></category>
		<category><![CDATA[Unit Test]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=103</guid>
		<description><![CDATA[W dzisiejszych czasach nikt już sobie nie wyobraża dobrze zaprojektowanej aplikacji biznesowej bez testów jednostkowych. Istnieją metodologie, które wręcz testy jednostkowe stawiają na pierwszym miejscu. Spring.NET idzie z duchem czasu i posiada wsparcie dla testów jednostkowych przy użyciu NUnit. Bądź co bądź to nadal najpopularniejszy framework testowy dla .NET, ale w zapowiedziach jest już wsparcie [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=103&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>W dzisiejszych czasach nikt już sobie nie wyobraża dobrze zaprojektowanej aplikacji biznesowej bez testów jednostkowych. Istnieją metodologie, które wręcz testy jednostkowe stawiają na pierwszym miejscu. Spring.NET idzie z duchem czasu i posiada wsparcie dla testów jednostkowych przy użyciu NUnit. Bądź co bądź to nadal najpopularniejszy framework testowy dla .NET, ale w zapowiedziach jest już wsparcie Spring.NET dla MbUnit i testów z Visual Studio.<br />
Każdy kto się zetknął z testami jednostkowymi niejednokrotnie narzekał na to, iż spory nakład pracy trzeba włożyć aby przygotować środowisko uruchomieniowe. Mam tu na myśli utworzenie odpowiednich instancji serwisów, wstrzykiwanie do nich zależności obiektów DAO, itp. Często (znam to z autopsji) z tego powodu rezygnowało się z testów szczególnie w mniejszych projektach.<br />
Wyobraźmy sobie najprostszy i najbardziej typowy scenariusz testów – testy serwisów warstwy biznesowej. Na pewno będziemy musieli zacząć od powołania instancji serwisów, a w następnej kolejności pomyśleć o zarządzaniu transakcjami, a także o tym czy wszystko wewnątrz serwisów zostało odpowiednio zainicjowane, tj. np. obiekty DAO.<br />
Na szczęście o tych zmartwieniach pozwala nam zapomnieć mechanizm integracji z testami NUnit w Spring.NET.<br />
Wygląda to dosyć prosto. Na początek informacja, że Spring.NET dostarcza nam klasy o nazwie AbstractDependencyInjectionSpringContextTests. Wystarczy, aby nasza klasa z testami dziedziczyła z tej klasy bazowej i przeciążyła właściwość ConfigLocations typu string[]. Jak można się domyślić ta właściwość zawiera wskazanie na pliki konfiguracyjne Spring.NET. Wygląda świetnie – przecież nikt nie będzie pisał plików dla kontenera IoC ponownie. Wykorzystajmy te z naszej aplikacji wskazując na nie.<br />
Spójrzmy na prosty przykład:</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
[TestFixture]<br />
public class AbonenciServiceTest : AbstractDependencyInjectionSpringContextTests<br />
{<br />
&nbsp;&nbsp;private AbonenciService abonenciService;<br />
&nbsp;&nbsp;public AbonenciService AbonenciService<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;set { abonenciService = value; }<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;protected override string[] ConfigLocations<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;get { return new String[] { &#8222;assembly://BeezDev.Turrow.Model.Test/BeezDev.Turrow.Model.Test/Services.xml&#8221; }; }<br />
&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;[Test]<br />
&nbsp;&nbsp;public void PobierzListeAbonentow()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;IList&lt;AbonentDTO&gt; listaAbonentow = this.abonenciService.PobierzListeAbonentow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Assert.AreEqual(0, listaAbonentow.Count);<br />
&nbsp;&nbsp;&nbsp;&nbsp;AbonentDTO abonentDTO = new AbonentDTO();<br />
&nbsp;&nbsp;&nbsp;&nbsp;abonentDTO.Id = Guid.NewGuid();<br />
&nbsp;&nbsp;&nbsp;&nbsp;abonentDTO.Imie = &#8222;Jan&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;abonentDTO.Nazwisko = &#8222;Kowalski&#8221;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;this.abonenciService.DodajAbonenta(abonentDTO);<br />
&nbsp;&nbsp;&nbsp;&nbsp;listaAbonentow = this.abonenciService.PobierzListeAbonentow();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Assert.AreEqual(1, listaAbonentow.Count);<br />
&nbsp;&nbsp;}<br />
}<br />
</span></td>
</tr>
</tbody>
</table>
<p>
Co tu widać? Dziedziczymy po wspomnianej klasie i uzupełniamy właściwość ConfigLocations wskazując nasz plik konfiguracyjny. W tym wypadku jest to tylko część konfiguracji dotycząca samych serwisów. Dzięki temu Spring.NET korzystając z konfiguracji zapisanej w Services.xml wstrzyknie nam instancję klasy AbonenciService odpowiednio ją inicjując.<br />
Tak wygląda plik Services.xml:
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243; ?&gt;<br />
&lt;objects xmlns=&#8221;http://www.springframework.net&#8221;&gt;<br />
&nbsp;&nbsp;&lt;object id=&#8221;abonenciService&#8221; type=&#8221;BeezDev.Turrow.Wspolne.Model.AbonenciService, BeezDev.Turrow.Wspolne.Model&#8221;&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=&#8221;AbonentDAO&#8221; ref=&#8221;abonentDAO&#8221;/&gt;<br />
&nbsp;&nbsp;&lt;/object&gt;</p>
<p>&nbsp;&nbsp;&lt;object id=&#8221;abonentDAO&#8221; type=&#8221;BeezDev.Turrow.Wspolne.DataAccess.AbonentDAO, BeezDev.Turrow.Wspolne.DataAccess&#8221;/&gt;</p>
<p>&lt;/objects&gt;<br />
</span></div>
<p>
Widzimy, że do serwisu dodatkowo została wstrzyknięta instancja klasy AbonentDAO.<br />
<br />
W zdecydowanej większości systemów biznesowych dane są zapisywane w jakimś repozytorium, którym najczęściej jest baza danych. Istotną kwestią jest to, że takie dane dodane czy zmodyfikowane podczas testu nie powinny mieć wpływu na całość systemu. Oznacza to tyle, że test powinien się wykonywać w transakcji i wszelkie modyfikacje danych nie powinny być widoczne poza tą transakcją. Takie właśnie zachowanie daje nam Spring.NET, tj. w ramach testu tworzy transakcję, a następnie ją wycofuje. Odpowiedzialna za to jest jedna z klas bazowych AbstractTransactionalDbProviderSpringContextTests. Klasa ta bazuje na IPlatformTransactionManager, który jest dostarczony w ramach konfiguracji aplikacji. W pewnych przypadkach takie domyślne zachowanie nie jest wskazane, dlatego też mamy możliwość dziedziczenia po tej klasie i wprowadzenia własnych modyfikacji. Może nas np. w szczególnych przypadkach interesować zatwierdzenie transakcji zamiast domyślnego jej wycofania. Można to osiągnąć poprzez wywołanie metody SetComplete(). Podobnie możemy chcieć wycofać transakcję przed zakończeniem testu – wywołując EndTransaction();<br />
<br />
Spring.NET dostarcza nam prosty, ale jakże pomocny mechanizm wsparcia dla testów jednostkowych NUnit. Pozwala nam to zaoszczędzić wiele cennego czasu przy budowaniu testów naszej aplikacji.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/103/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/103/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/103/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=103&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/08/06/ugryzc-spring-net-%e2%80%93-cz-7-testy-jednostkowe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Ugryźć Spring.NET – (Cz.6) Serwisy</title>
		<link>http://beniaminzaborski.wordpress.com/2009/07/29/ugryzc-spring-net-%e2%80%93-cz-6-serwisy/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/07/29/ugryzc-spring-net-%e2%80%93-cz-6-serwisy/#comments</comments>
		<pubDate>Wed, 29 Jul 2009 18:28:23 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Ugryźć Spring.Net]]></category>
		<category><![CDATA[.NET Remoting]]></category>
		<category><![CDATA[CAO]]></category>
		<category><![CDATA[SAO]]></category>
		<category><![CDATA[Service]]></category>
		<category><![CDATA[Sigleton]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=83</guid>
		<description><![CDATA[Współczesne systemy informatyczne to systemy rozproszone, które komunikują się ze sobą na wiele różnych sposobów. U podstaw takiej komunikacji leżą interfejsy, za pomocą których systemy będą się ze sobą komunikować. Interfejsy odgrywają tu rolę fasad i to właśnie je określamy mianem serwisów. Ta część serii będzie traktować właśnie o możliwościach jakie daje nam Spring.NET w [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=83&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Współczesne systemy informatyczne to systemy rozproszone, które komunikują się ze sobą na wiele różnych sposobów. U podstaw takiej komunikacji leżą interfejsy, za pomocą których systemy będą się ze sobą komunikować. Interfejsy odgrywają tu rolę fasad i to właśnie je określamy mianem serwisów. Ta część serii będzie traktować właśnie o możliwościach jakie daje nam Spring.NET w kwestii serwisów. O samym wzorcu projektowym Service Layer Martin Fowler pisze tutaj: <a title="http://martinfowler.com/eaaCatalog/serviceLayer.html" href="http://martinfowler.com/eaaCatalog/serviceLayer.html" target="_blank">http://martinfowler.com/eaaCatalog/serviceLayer.html</a>.</p>
<p>W świecie .NET mamy do dyspozycji kilka różnych technologii pozwalających budować i publikować nam serwisy jak: .NET Remoting, WebServices, Enterprise Services czy wreszcie WCF.</p>
<p>Na etapie projektu aplikacji często nie wiemy lub nie chcemy się zajmować takimi konkretami jak technologia, której użyjemy do budowy naszych serwisów. Na tym etapie podchodzimy do serwisów w sposób bardziej abstrakcyjny. Jednak przychodzi moment, gdy musimy się zdecydować na któreś z rozwiązań. Załóżmy, że w pierwszej kolejności wybieramy .NET Remoting, ale po dłuższym zastanowieniu stwierdzamy jednak, że nasze serwisy będą wystawione na świat w postaci WebService i hostowane na serwerze IIS. Taka zmiana wymagać będzie od nas pewnego nakładu pracy i często wprowadza lekkie zamieszanie. A co gdyby tylko na poziomie konfiguracji określać jaką technologią nasze serwisy mają być hostowane? Brzmi świetnie!!! <br />Tu z pomocą przychodzi Spring.NET, a właściwie cały mechanizm eksporterów serwisów w Spring.NET. <br />Spring.NET wprowadza kolejną warstwę abstrakcji – eksportera serwisu. Obsługuje wszystkie wymienione wcześniej technologie eksportowania serwisów. Cała konfiguracja, która pozwoli nam wyeksportować serwis jest zupełnie banalna.</p>
<p>Zacznijmy od zdefiniowania dosłownie interfejsu naszego serwisu IAbonenciService.</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
public interface IAbonenciService<br />
{<br />
&nbsp;&nbsp;IList&lt;AbonentDTO&gt; PobierzListeAbonentow();<br />
}<br />
</span></td>
</tr>
</tbody>
</table>
<p>Mamy bardzo prosty interfejs serwisu tylko z jedną metodą, teraz czas na jego implementację.</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
public class AbonenciService : IAbonenciService<br />
{<br />
&nbsp;&nbsp;#region DAOs</p>
<p>&nbsp;&nbsp;private AbonentDAO abonentDAO;<br />
&nbsp;&nbsp;public AbonentDAO AbonentDAO<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;get { return abonentDAO; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;set {abonentDAO = value; }<br />
&nbsp;&nbsp;}</p>
<p>&nbsp;&nbsp;#endregion DAOs</p>
<p>&nbsp;&nbsp;public IList&lt;AbonentDTO&gt; PobierzListeAbonentow()<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;IList&lt;AbonentDTO&gt; listaAbonentow = new List&lt;AbonentDTO&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;foreach(Abonent abonent in AbonentDAO.PobierzListeAbonentow())<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;listaAbonentow.Add(AbonentConverter.ToAbonentDTO(abonent));<br />
&nbsp;&nbsp;&nbsp;&nbsp;return listaAbonentow;<br />
&nbsp;&nbsp;}<br />
}</p>
<p></span></td>
</tr>
</tbody>
</table>
<p>
Przedstawiłem prostą implementację serwisu, odwołująca się do obiektu DAO jak i obiektu konwertera. Oczywiście instancje obu tych obiektów możemy sobie wstrzyknąć poprzez kontener IoC Springa.</p>
<p>Dodać należy, że dobrym rozwiązaniem będzie umieszczenie interfejsu serwisu w osobnym assembly, np. BeezDev.ExampleSpringApp.Model.Interface, a implementacji w osobnym, np. BeezDev.ExampleSpringApp.Model. Dzięki temu aplikacja klienta będzie posiadała jawną referencję tylko do assembly z interfejsem, a nie implementacją serwisu.</p>
<p>Spróbujmy opublikować nasz serwis poprzez .NET Remoting. Nie będę opisywał szczegółów samej technologii .NET Remoting, bo moim celem jest pokazanie jedynie integracji Spring.NET z .NET Remoting. W sprawie konfiguracji kanałów, portów, aktywacji obiektów (SAO, SAO Singleton, CAO) odsyłam do dokumentacji.</p>
<p>Na pierwszy ogień konfiguracja po stronie serwera. Załóżmy, że nasz serwis hostujemy w zwykłej aplikacji .NET uruchamianej w postaci usługi Windows. Konfiguracja Spring.NET wyglądać będzie następująco:
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;abonentDAO&#8221; type=&#8221;BeezDev.ExampleSpringApp.Model.AbonentDAO, BeezDev.ExampleSpringApp.Model&#8221;&gt;<br />
&lt;/object&gt;</p>
<p>&lt;object id=&#8221;abonenciService&#8221; type=&#8221;BeezDev.ExampleSpringApp.Model.AbonenciService, BeezDev.ExampleSpringApp.Model&#8221;&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;AbonentDAO&#8221; value=&#8221;abonentDAO&#8221; /&gt;<br />
&lt;/object&gt;</p>
<p>&lt;object name=&#8221;saoSingletonAbonenciService &#8221; type=&#8221;Spring.Remoting.SaoExporter, Spring.Services&#8221;&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;TargetName&#8221; value=&#8221; abonenciService&#8221; /&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;ServiceName&#8221; value=&#8221;AbonenciService&#8221; /&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>
Co widzimy? Na początek wspomniany wcześniej obiekt typu DAO, dalej definicja serwisu i wstrzyknięcie instancji obiektu DAO. Najciekawsze na koniec – eksport serwisu poprzez .NET Remoting jako SAO Singleton. Właściwość TargetName wskazuje na definicję serwisu, a ServiceName określa nazwę pod jaką będzie widoczny nasz serwis.</p>
<p>To prawie wszystko! Prawie bo reszta to już tylko konfiguracja .NET Remoting, tj.
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;system.runtime.remoting&gt;<br />
&nbsp;&nbsp;&lt;application&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;channels&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;channel ref=&#8221;tcp&#8221; port=&#8221;8008&#8243; /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/channels&gt;<br />
&nbsp;&nbsp;&lt;/application&gt;<br />
&lt;/system.runtime.remoting&gt;<br />
</span></div>
<p>
Po stronie aplikacji klienta konfiguracja jest równie prosta:
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;abonenciService&#8221; type=&#8221;Spring.Remoting.SaoFactoryObject, Spring.Services&#8221;&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;ServiceInterface&#8221; value=&#8221;BeezDev.ExampleSpringApp.Model.IAbonenciService, BeezDev.ExampleSpringApp.Model.Interface&#8221; /&gt;<br />
&nbsp;&nbsp;&lt;property name=&#8221;ServiceUrl&#8221; value=&#8221;tcp://localhost:8008/AbonenciService&#8221; /&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>
Pobranie naszego serwisu po url-u, gdzie protokół (tcp) i port (8008) zdefiniowaliśmy w konfiguracji Remotingu po stronie serwera oczywiście. Nazwa serwisu w url to ta którą podaliśmy w ServiceName.</p>
<p>Konfiguracja .NET Remoting po stronie klienta:
</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;system.runtime.remoting&gt;<br />
&nbsp;&nbsp;&lt;application&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;channels&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;channel ref=&#8221;tcp&#8221;/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;/channels&gt;<br />
&nbsp;&nbsp;&lt;/application&gt;<br />
&lt;/system.runtime.remoting&gt;<br />
</span></div>
<p>
Oto cała konfiguracja, teraz możemy pobrać po stronie klienta instancję serwisu, przy założeniu że aplikacja serwera hostująca nasz serwis jest uruchomiona.</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
IApplicationContext ctx = ContextRegistry.GetContext();<br />
IAbonenciService abonenciService = (IAbonenciService)ctx.GetObject(&#8222;abonenciService&#8221;);<br />
IList&lt;AbonentDTO&gt; listaAbonentow = abonenciService.PobierzListeAbonentow();<br />
</span></td>
</tr>
</tbody>
</table>
<p> To wszystko i działa! Jeśli zdecydujemy opublikować nasz serwis za pomocą innej technologii praktycznie wszystkie zmiany jakich musimy dokonać ograniczą się do zmian exportera w plikach konfiguracyjnych. Po szczegóły związane z serwisami w Spring.NET odsyłam tradycyjnie do dokumentacji projektu.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/83/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/83/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/83/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=83&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/07/29/ugryzc-spring-net-%e2%80%93-cz-6-serwisy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>Ugryźć Spring.Net &#8211; (cz.5) Zarządzanie transakcjami</title>
		<link>http://beniaminzaborski.wordpress.com/2009/05/21/ugryzc-spring-net-cz-5-zarzadzanie-transakcjami/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/05/21/ugryzc-spring-net-cz-5-zarzadzanie-transakcjami/#comments</comments>
		<pubDate>Thu, 21 May 2009 20:00:07 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Ugryźć Spring.Net]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=59</guid>
		<description><![CDATA[Czas zająć się wreszcie kwestią istotną, ale często traktowaną przez wielu z nas po macoszemu, mianowicie transakcjami, a w zasadzie to zarządzaniem transakcjami. Każdy zdaję sobie sprawę z tego, że jest to bardzo ważny temat, ale nie do końca poświęcamy mu odpowiednią ilość czasu. W tym artykule chciałbym przybliżyć cały mechanizm zarządzania transakcjami jaki daje [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=59&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Czas zająć się wreszcie kwestią istotną, ale często traktowaną przez wielu z nas po macoszemu, mianowicie transakcjami, a w zasadzie to zarządzaniem transakcjami. Każdy zdaję sobie sprawę z tego, że jest to bardzo ważny temat, ale nie do końca poświęcamy mu odpowiednią ilość czasu. W tym artykule chciałbym przybliżyć cały mechanizm zarządzania transakcjami jaki daje nam Spring.NET.</p>
<p>To co powinno nas na początku zainteresować to interfejs IPlatformTransactionManager, który wygląda tak:</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
public interface IPlatformTransactionManager<br />
{<br />
  ITransactionStatus GetTransaction( ITransactionDefinition definition );<br />
  void Commit( ITransactionStatus transactionStatus );<br />
  void Rollback( ITransactionStatus transactionStatus );<br />
}<br />
</span></td>
</tr>
</tbody>
</table>
<p>Spring.Net dostarcza kilka różnych implementacji tego interfejsu, tj.:</p>
<ul>
<li>AdoPlatformTransactionManager – obsługa lokalnych transakcji ADO.NET</li>
<li>ServiceDomainPlatformTransactionManager – obsługa transakcji rozproszonych bazujących na menadżerze Enterprise Services</li>
<li>TxScopePlatformTransactionManager – obsługa transakcji lokalnych i zdalnych bazująca na System.Transactions</li>
<li>HibernatePlatformTransactionManager – obsługa transakcji lokalnych dla NHibernate i ADO.NET</li>
</ul>
<p>Jak widać metoda GetTransaction zwraca odpowiedni obiekt implementujący interfejs ITransactionStatus w zależności od przekazanych parametrów (ITransactionDefinition). Dzięki temu obiekt ITransactionStatus może reprezentować nową lub już istniejącą transakcję.</p>
<p>Co zatem określa obiekt ITransactionDefinition? Przyjrzyjmy się temu bliżej. Oto co definiuje:</p>
<ul>
<li>Isolation – poziom izolacji transakcji</li>
<li>Propagation – pozwala określić czy ma zostać utworzona nowa transakcja czy kod ma być wykonany w istniejącej transakcji</li>
<li>Timeout – czas działania transakcji po jakim zostanie zgłoszony błąd przekroczenia czasu oczekiwania</li>
<li>Read-only – ważna właściwość określająca, że dane w transakcji nie będą modyfikowane. Ma to szczególne znaczenie w przypadku NHibernate, bo podnosi wydajność takiej transakcji.</li>
</ul>
<p>ITransactionStatus zwracany z metody GetTransaction określa status transakcji i niejako jej kontekst wykonania. Zauważmy, że parametr tego typu przyjmują metody Commit i Rollback interfejsu IPlatformTransactionManager.</p>
<p>Najprostszym sposobem powołania do życia menadżera transakcji jest zlecenie tego kontenerowi IoC. W wypadku prostego menadżera dla lokalnych transakcji ADO.NET plik konfiguracyjny wygląda tak:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;objects xmlns=&#8217;http://www.springframework.net&#8217; xmlns:db=&#8221;http://www.springframework.net/database&#8221;&gt;<br />
  &lt;db:provider id=”DbProvider”<br />
  provider=”SqlServer-2.0&#8243;<br />
  connectionString=”Data Source=BENIAMINZ\SQLEXPRESS;Initial Catalog=ADMINET;Integrated Security=SSPI;”/&gt;<br />
  &lt;object id=&#8221;TransactionManager&#8221; type=&#8221;Spring.Data.AdoPlatformTransactionManager, Spring.Data&#8221;&gt;<br />
    &lt;property name=&#8221;DbProvider&#8221; ref=&#8221;DbProvider&#8221;/&gt;<br />
  &lt;/object&gt;<br />
&lt;/objects&gt;<br />
</span></div>
<p>Jedyne co wymaga wyjaśnienia to DbProvider, ale jego już używaliśmy niejednokrotnie. Menadżerowi transakcji wystarczy przekazać referencję do odpowiedniego DbProvider, który jak widać na przykładzie jest zdefiniowany wyżej.</p>
<p>W wypadku menadżera transakcji bazującego na System.Transactions plik konfiguracyjny wyglądałby dużo prościej:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;TransactionManager&#8221; type=&#8221;Spring.Data.TxScopeTransactionManager, Spring.Data&#8221;&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>Tu już nie przekazujemy DbProvidera, ponieważ mechanizm typu System.Transactions to rozproszony system zarządzania transakcjami.</p>
<p>Jeszcze inaczej się przedstawia konfiguracja menadżera transakcji dla NHibernate:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;HibernateTransactionManager&#8221; type=&#8221;Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate&#8221;&gt;<br />
  &lt;property name=&#8221;DbProvider&#8221; ref=&#8221;DbProvider&#8221;/&gt;<br />
  &lt;property name=&#8221;SessionFactory&#8221; ref=&#8221;MySessionFactory&#8221;/&gt;<br />
&lt;/object&gt;<br />
</span></div>
<p>Podobnie jak w wypadku tego pierwszego przekazujemy DbProvidera, ale jeszcze dodatkowo musimy wskazać na odpowiedni SessionFactory. SessionFactory definiowaliśmy w części poświęconej dostępowi do danych poprzez NHibernate, więc nie będę tego ponownie przedstawiał.</p>
<p>Zarządzanie transakcjami w Spring.Net jest możliwe na dwa sposoby: deklaratywnie i imperatywnie. Jak podaje dokumentacja większość użytkowników wybiera sposób deklaratywny. Hmm … ja też! Podstawowy powód mojego wyboru jest taki, iż ta metoda wymaga naprawdę niewiele wysiłku, a także i może przede wszystkim, nie „wplątuje” się w kod logiki biznesowej aplikacji.<br />
Dodatkowe cechy deklaratywnej obsługi transakcji w Spring.NET to możliwość definiowania własnych reguł wycofywania transakcji, czy możliwość kontrolowania procesu działania transakcji, tj. np. wykonania dodatkowego kodu podczas rollback. Możliwe jest to dzięki temu, iż deklaratywna obsługa transakcji opiera się na AOP.</p>
<p>W typowych przypadkach transakcje powinniśmy stosować na poziomie komponentów biznesowych czy serwisów pełniących rolę fasad. Nie stosujemy transakcji na niższym poziomie abstrakcji, tj, bezpośrednio w obiektach dostępu do danych. Przedstawię prosty przykład serwisu:</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
public class AbonenciService : IAbonenciService<br />
{<br />
  private AbonentDAO abonentDAO;<br />
  public AbonentDAO AbonentDAO<br />
  {<br />
    get { return abonentDAO; }<br />
    set { abonentDAO = value; }<br />
  }</p>
<p>&nbsp;&nbsp;[Transaction()]<br />
  public void DodajAbonenta(AbonentDTO abonentDTO)<br />
  {<br />
    AbonentDAO.Zapisz(AbonentConverter.ToAbonent(abonentDTO));<br />
  }<br />
}            </p>
<p></span></td>
</tr>
</tbody>
</table>
<p>Jak widać jedyne co musimy zrobić to opatrzyć metodę serwisu atrybutem [Transaction()]. Tutaj został użyty najprostszy przypadek, ale można również na tym poziomie określić dodatkowe cechy transakcji jak: poziom izolacji, to czy transakcja ma być read-only, itp.</p>
<p>Przyjrzyjmy się teraz przykładowi kodu z poprzedniej części serii poszerzonemu o definicję naszego serwisu:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;spring&gt;<br />
  &lt;parsers&gt;<br />
    &lt;parser type=&#8221;Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services&#8221; /&gt;<br />
    &lt;parser type=&#8221;Spring.Data.Config.DatabaseNamespaceParser, Spring.Data&#8221; /&gt;<br />
    &lt;parser type=&#8221;Spring.Transaction.Config.TxNamespaceParser, Spring.Data&#8221; /&gt;<br />
  &lt;/parsers&gt;<br />
  &lt;context&gt;<br />
    &lt;resource uri=&#8221;config://spring/objects&#8221; /&gt;<br />
  &lt;/context&gt;<br />
  &lt;objects xmlns=&#8221;http://www.springframework.net&#8221;<br />
  xmlns:db=&#8221;http://www.springframework.net/database&#8221;<br />
  xmlns:tx=&#8221;http://www.springframework.net/tx&#8221;&gt;</span></div>
<div><span style="font-family:Courier New;color:#0000ff;">    &lt;db:provider id=&#8221;DbProvider&#8221;<br />
    provider=&#8221;SqlServer-2.0&#8243;<br />
    connectionString=&#8221;Data Source=BENIAMINZ\SQLEXPRESS;Initial Catalog=ADMINET;Integrated Security=SSPI;&#8221;/&gt;</span></div>
<div><span style="font-family:Courier New;color:#0000ff;">    &lt;object id=&#8221;NHSessionFactory&#8221; type=&#8221;Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate12&#8243;&gt;<br />
    &lt;property name=&#8221;DbProvider&#8221; ref=&#8221;DbProvider&#8221;/&gt;<br />
    &lt;property name=&#8221;MappingAssemblies&#8221;&gt;<br />
      &lt;list&gt;<br />
        &lt;value&gt;BizDev.SimpleSpringApplication&lt;/value&gt;<br />
      &lt;/list&gt;<br />
    &lt;/property&gt;<br />
    &lt;property name=&#8221;HibernateProperties&#8221;&gt;<br />
      &lt;dictionary&gt;<br />
        &lt;entry key=&#8221;hibernate.connection.provider&#8221;<br />
        value=&#8221;NHibernate.Connection.DriverConnectionProvider&#8221;/&gt;<br />
        &lt;entry key=&#8221;hibernate.dialect&#8221;<br />
        value=&#8221;NHibernate.Dialect.MsSql2005Dialect&#8221;/&gt;<br />
        &lt;entry key=&#8221;hibernate.connection.driver_class&#8221;<br />
        value=&#8221;NHibernate.Driver.SqlClientDriver&#8221;/&gt;<br />
        &lt;entry key=&#8221;hibernate.current_session_context_class&#8221;<br />
        value=&#8221;Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate12&#8243;/&gt;<br />
      &lt;/dictionary&gt;<br />
    &lt;/property&gt;<br />
  &lt;/object&amp;gt</p>
<p>&nbsp;&nbsp;&lt;object id=”transactionManager” type=”Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate12″&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=”DbProvider” ref=”DbProvider”/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;property name=”SessionFactory” ref=”NHSessionFactory”/&gt;<br />
&nbsp;&nbsp;&lt;/object&gt;</p>
<p>&nbsp;&nbsp;&lt;object id=&#8221;AbonentDao&#8221; type=&#8221;BizDev.SimpleSpringApplication.AbonentDAO, BizDev.SimpleSpringApplication&#8221;&gt;<br />
    &lt;property name=&#8221;SessionFactory&#8221; ref=&#8221;NHSessionFactory&#8221;/&gt;<br />
  &lt;/object&gt;<br />
 <br />
  &lt;object id=”AbonenciService” type=”BizDev.SimpleSpringApplication.AbonenciService, BizDev.SimpleSpringApplication”&gt;<br />
    &lt;property name=”AbonentDao” ref=”AbonentDao”/&gt;<br />
  &lt;/object&gt;</span></div>
<div><span style="font-family:Courier New;color:#0000ff;">  &lt;tx:attribute-driven/&gt;</span></div>
<div><span style="font-family:Courier New;color:#0000ff;">  &lt;/objects&gt;<br />
&lt;/spring&gt;</span></div>
<p>To jest kompletny w pełni działający przykład na którym można dostrzec: obiekt dostępu do danych, serwis, provider bazy danych, NHibernate-owe SessionFactory oraz to co nas interesuje najbardziej czyli menadżer transakcji dla NHibernate. Wyjaśnienia wymaga jeszcze wpis &lt;tx:attribute-driven/&gt;, który jest niezbędny dla deklaratywnego mechanizmu zarządzania transakcjami. Tutaj został zdefiniowany z domyślnymi parametrami, tj. wskazuje na menadżera transakcji o domyślnej nazwie „transactionManager”. Jeżeli ta nazwa byłaby inna wtedy musielibyśmy to określić tak:</p>
<div><span style="font-family:Courier New;color:#0000ff;"><br />
&lt;object id=&#8221;nhTransactionManager&#8221; type=”Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate12&#8243;&gt;<br />
  &lt;property name=”DbProvider” ref=”DbProvider”/&gt;<br />
  &lt;property name=”SessionFactory” ref=”NHSessionFactory”/&gt;<br />
&lt;/object&gt;<br />
&lt;tx:attribute-driven transaction-manager=”nhTransactionManager”/&gt;<br />
</span></div>
<p>Inna metoda obsługi transakcji w Spring.NET to metoda imperatywna, czyli programowa. To ta mniej preferowana przeze mnie. Do zarządzania transakcjami w ten sposób możemy skorzystać z jednego z dwóch rozwiązań:</p>
<ul>
<li>TransactionTemplate</li>
<li>IPlatformTransactionManager</li>
</ul>
<p>Pierwsza metoda polega na stosowaniu anonimowych delegatów. Prawda, że ten kod nie wygląda przyjemnie?</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;"><br />
tt.Execute(delegate(ITransactionStatus status)<br />
{<br />
  try<br />
  {<br />
    AbonentDAO.Zapisz(abonent);<br />
  } catch (Exception ex)<br />
  {<br />
    status.RollbackOnly = true;<br />
  }<br />
  return null;<br />
});<br />
</span></td>
</tr>
</tbody>
</table>
<p>Drugie podejście to użycie klasy implementującej IPlatformTransactionManager. Interfejs IPlatformTransactionManager już znamy. Spójrzmy na samo opisujący się przykład, gdzie transactionManager implementuje wspomniany interfejs:</p>
<table id="C#" border="0" cellspacing="10" width="100%" bgcolor="#eeeeee">
<tbody>
<tr>
<td valign="top"><span style="font-family:Courier New;">DefaultTransactionDefinition def = new DefaultTransactionDefinition();<br />
def.PropagationBehavior = TransactionPropagation.Required;<br />
ITransactionStatus status = transactionManager.GetTransaction(def);<br />
try<br />
{<br />
  AbonentDAO.Zapisz(abonent);<br />
}<br />
catch (Exception e)<br />
{<br />
  transactionManager.Rollback(status);<br />
  throw;<br />
}<br />
transactionManager.Commit(status);   <br />
</span></td>
</tr>
</tbody>
</table>
<p>Wygląda prosto i tak też jest w rzeczywistości. Pobieramy instancję ItransactionStatus, a następnie wykonujemy commit na sukces lub rollback w wypadku niepowodzenia przekazując ją jako parametr.</p>
<p>Spring.NET daje nam świetny mechanizm zarządzania transakcjami i zwalania nas od implementowania własnych rozwiązań pozwalając skupić się na właściwym biznesie aplikacji.<br />
Dokumentacja Spring.Net omawia jeszcze szczegółowo wiele aspektów zarządzania transakcjami. Zainteresowanych samym działaniem mechanizmu od kuchni oraz tym jaką rolę w tym wszystkim odgrywa AOP odsyłam do dokumentacji.<br />
W kolejnej części omówię stosowanie serwisów w aplikacjach rozproszonych Spring.NET.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/59/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/59/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/59/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=59&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/05/21/ugryzc-spring-net-cz-5-zarzadzanie-transakcjami/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
		<item>
		<title>DO or not DO?</title>
		<link>http://beniaminzaborski.wordpress.com/2009/05/13/do-or-not-do/</link>
		<comments>http://beniaminzaborski.wordpress.com/2009/05/13/do-or-not-do/#comments</comments>
		<pubDate>Wed, 13 May 2009 07:06:24 +0000</pubDate>
		<dc:creator>Beniamin Zaborski</dc:creator>
				<category><![CDATA[Codzienne dylematy modelarza]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[3-Tier]]></category>
		<category><![CDATA[Data Transfer Object]]></category>
		<category><![CDATA[Design Pattern]]></category>
		<category><![CDATA[Framework]]></category>

		<guid isPermaLink="false">http://beniaminzaborski.wordpress.com/?p=26</guid>
		<description><![CDATA[DO or not DO? DO jak Data Object, zwane także DTO &#8211; Data Transfer Object, VO &#8211; Value Object czy nawet Presentation Entity. Używać czy nie używać? Oczywiście nie spodziewajcie się jednoznacznej odpowiedzi, a jeśli już taka padnie to pewnie będzie dość subiektywna. Problem ten przewija się na wielu forach i stosowanie obiektów DTO ma [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=26&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>DO or not DO? DO jak Data Object, zwane także DTO &#8211; Data Transfer Object, VO &#8211; Value Object czy nawet Presentation Entity. Używać czy nie używać?<br />
Oczywiście nie spodziewajcie się jednoznacznej odpowiedzi, a jeśli już taka padnie to pewnie będzie dość subiektywna. Problem ten przewija się na wielu forach i stosowanie obiektów DTO ma tyle samo przeciwników co zwolenników. Dużo zależy jednak od aplikacji jaką piszemy, od jej typu, rozmiaru, itp. Ja jednak obecnie zaliczam się do grupy zwolenników stosowania obiektów DTO (choć może mnie ktoś przekona i zmienię zdanie). Czemu? To postaram się właśnie tutaj przedstawić. Zanim jednak zacznę należy się krótkie wprowadzenie teoretyczne.<br />
Czasy gdzie dominującym modelem architektonicznym w aplikacjach biznesowych był klient-serwer bezpowrotnie (mam nadzieję) minęły. Dziś przystępując do projektu z góry zakładamy model n-warstwowy (szczególnie 3-warstwowy). Oznacza to, że w naszej aplikacji będzie można wyróżnić co najmniej następujące warstwy logiczne:<br />
- warstwa dostępu do danych<br />
- warstwa logiki biznesowej<br />
- warstwa prezentacji.<br />
Jest to model bardzo ogólny i odnosi się do wszystkich typów aplikacji czy to web-owych czy desktopowych. W kontekście poruszanego tematu nas najbardziej będzie interesować styk warstwy logiki biznesowej i warstwy prezentacji.<br />
Nasuwa się pytanie: czy do warstwy prezentacji przesyłać bezpośrednio encje biznesowe? Ja jednak postawię to pytanie inaczej: dlaczego nie przesyłać do warstwy prezentacji encji biznesowych?<br />
Jak już wspomniałem wcześniej jestem zwolennikiem stosowania obiektów DTO. Zdaję sobie sprawę, że wymaga to dodatkowej pracy (co często wytykają przeciwnicy), ale to procentuje później.<br />
Warto zerknąć <a href="http://martinfowler.com/eaaCatalog/dataTransferObject.html">tutaj</a> i zobaczyć jak Martin Fowler przedstawia Data Transfer Object.</p>
<p>Oto co przemawia za tym rozwiązaniem:</p>
<p>1) <strong>Luźnie powiązania.</strong></p>
<p>Podstawową zaletą takiego rozwiązania jest wprowadzenie kolejnego luźniejszego powiązania pomiędzy warstwą logiki biznesowej, a prezentacji. Ma to szczególne znaczenie, kiedy nagle okaże się, iż trzeba dokonać pewnych zmian w warstwie prezentacji. W ten sposób często unikamy modyfikacji w warstwie logiki biznesowej, co wydaje się być dobre.</p>
<p><strong>Przeciwnicy powiedzą: <em>W większości typowych przypadków i tak dokonanie zmian w warstwie logiki biznesowej będzie niezbędne.</em></strong></p>
<p>2) <strong>Różne wymagania.</strong></p>
<p>Encja reprezentująca jakiś fragment naszego biznesu z jednej strony musi komunikować się z klientem (warstwa prezentacji), a z drugiej z repozytorium w którym jest przechowywana (warstwa dostępu do danych). Oba te wymagania nakładają na encje pewne zadania. Patrząc od strony warstwy dostępu do danych to powinno być możliwe wykonanie operacji CRUD na encji. Czy to poprzez procedury składowane, czy mechanizm O/R Mapping-u. Z drugiej strony encja powinna współpracować z warstwą prezentacji, tj. bindować się z kontrolkami, obsługiwać mechanizmy powiadamiania o niespełnionych regułach walidacyjnych itp. To znowu nakłada na każdą encje zupełnie inne zadania. Stąd warto rozdzielić te dwa jakże odmiene od siebie grupy zadań, powierzając komunikację z warstwą prezentacji właśnie specjalnie do tego wydzielonym obiektom DTO.</p>
<p><strong>Przeciwnicy powiedzą: <em>Zbyt duży nakład pracy, a korzyści nie tak widoczne jak by się można było tego spodziewać.</em></strong></p>
<p>3) <strong>Większa wydajność.</strong></p>
<p>W czasach systemów rozproszonych często warstwy aplikacji znajdują się na różnych maszynach stąd komunikują się poprzez sieć. Komunikacja ta może się odbywać z wykorzystaniem różnych mechanizmów jak WebService (SOAP), .NET Remoting, COM+, itp. Często do pojedynczych widoków w warstwie prezentacji przesyłamy tylko część danych z encji. Nie zawsze encje pokrywają się 1 do 1 z widokami. Zamiast przesyłać poprzez sieć duże obiekty encji biznesowych warto przepakować do obiektów DTO tylko te dane, które faktycznie będą nam potrzebne w widoku.</p>
<p><strong>Przeciwnicy powiedzą: <em>W dzisiejszych czasach wydajność systemów to nie problem, zresztą kto na to zwraca uwagę.</em></strong></p>
<p>Jak napisałem na początku odpowiedzi jednoznacznej nie ma. Bez dwóch zdań koszty pracy związane ze stosowaniem obiektów DTO są wyższe, no  przynajmniej na początku. Warto rozważyć, przed przystąpieniem do nowego projektu, stosowanie obiektów DTO, co nie oznacza, że w każdym przypadku będzie to trafione rozwiązanie. A więc pytanie &#8222;DO or not DO&#8221; pozostaje otwarte &#8230;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/beniaminzaborski.wordpress.com/26/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/beniaminzaborski.wordpress.com/26/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/beniaminzaborski.wordpress.com/26/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=beniaminzaborski.wordpress.com&amp;blog=7810229&amp;post=26&amp;subd=beniaminzaborski&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://beniaminzaborski.wordpress.com/2009/05/13/do-or-not-do/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/0f20cb9d360868deb4273fabeae4b6f6?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">beniaminzaborski</media:title>
		</media:content>
	</item>
	</channel>
</rss>
