Hej, En två lagerslösning är nästan asp.net direkt mot databasen och där placerar du inte några entiteter alls utan jobbar med tex dataset. Ok tack, låter klokt Jag är inte rikitgt familjär med uttrycket "Manager" inte hört det i design-sammanhang förut. Men jag jobbar på ett liknande sätt med S K repositories http://www.martinfowler.com/eaaCatalog/repository.html Ok jag är lite trög här, men jag ska se om jag fattar =) Lyckas inte hitta några exempel på implementationer av den. Robin. Bra timing, jag satt just och funderade över om jag skulle ha datatables eller readers. Tack ;) Patrik, har du lust att definiera "entiteter", "repositories", "factories" och "tablemodules"? De är obekanta för mig. J Normén, varför inte Datasets? Det är ju en entitetstyp. Man kan kombinera med en egen klass som har Readers också, för att hämta långa listor o dyl. Jag använder inte alltid DS själv men i ett projekt valde vi detta och det har funkat väldigt bra. Det går snabbt att bygga ut klasserna också, man slipper ju all denna kod: Jag blev lite fundersam till hur man gör när man returnerar DataReaders från datalagret. DataReaders är ju uppkopplad mot databasen hela tiden och varför vill man då skicka en uppkopplad anslutning mellan lagren? Robin, det vill man eftersom det är snabbast. Men det beror på om dina lager finns inom samma process eller går över processgränser. Om du går över processgränser vill du INTE ha en datareader. Då är det entitetsobjekt som gäller. Om du gör komponenter som ingår i din Web-appl, då lever dessa i <b>samma process</b> (IIS) och inom samma Dotnet-applikation och då är Datareader optimalt. Ok då är jag med, tack! Här har jag förklarat Entities, Factories, Repositories och lite andra begrepp: http://www.cornerstone.se/news/showArticle.aspx?artID=83 TableModule kan man läsa om här: http://www.martinfowler.com/eaaCatalog/tableModule.html Hur sköter man stängningen av anslutningen. Om jag returnerar en datareader från datalagret till affärslagret så måste ju datalagret sköta stängningen av anslutningen. Och då måste ju affärslagret på något sätt ha tillgång till Command-objektet. det behövs inte, man kan skicka med en flagga som gör så att connection stängs när readern stängs: Ola o Robin. Johan N, jag håller inte riktigt med dig. Har du mätt upp med empiriska studier hur "otroligt stort" ett Dataset är i minnet? ;) Jag upplever det inte som farligt stort, om man tittar på den kod som skapas av ett typat dataset så ser det ganska vettig ut, enligt min mening. Sen har vi väl sällan flaskhalsen i RAM-minnet. Om dina affärsobjekt tar upp i snitt 1kb och mina 1,3kb så kommer det sannolikt inte att märkas av någon användare.. Ola. <b>>[...] och för mig har produktiviteten samt fel minimerats [...]</b> haha. skrev fel... kul... haha... En fråga till dök upp Du har entiteterna i affärslagret. "När du sparar skickar du in Article köär du en SP så anger du bara parametrarna efter Areticles värden." Nix för du använder datalagret i ditt affärslager. Johan, så här har vi använt DS i ett proj och jag tycker det har funkat bra. Ang DataSets storlek. Det är lite intressant hur ni placerar era olika klasser i de olika lagrena. Hej Jakob. Okej. Starkt knytna blir de om du gör dem starkt knutna... Eh, Om man använder Microsofts Data Application Block för att sköta databaskopplingen i datalagret och sen använder det för att skapa objekten i Repositories som ligger i affärslagret så får man automatiskt en stark koppling till relationsdatabaser? Eftersom Data Application Block är gjort för relationsdatabaser.. Så om man teoretiskt vill ha möjligheten att byta till XML eller dylikt så är inte det en bra lösning. ja. Vanligtvis använder man Inteface och Factories för att abstrahera bort beroenden. Och nej förresten "massa mer kod" lär det inte krävas, bara annorlunda mer generell kod. Som möjligtivs kan vara lite svår att skriva om man inte är van men mycket mer blir det nog inte. Okej.Tvålagerslösning
Kort fråga, pratar webblagret (klassen i aspx.cs-filen) direkt med dataacesslagret i en tvålagerslösning? Vart placerar man entiteterna lämpligast? I datalagret eller som ett eget lager som både vyn och datalagret kan använda?Sv: Tvålagerslösning
Jag föreslår alltid att man har minst tre lager så att man kan skilja på presentationslogik (asp.net), affärslogik (entiteter / repositories / factories / tablemodules) och datat, det brukar underlätta för underhåll och utökning. Sv:Tvålagerslösning
Fick ett annat tips om att bygga entiteter i managers i affärslagret och sköta flödet med controllers. Vad innebär detta mer konkret? Att jag från vyn anropar en controller som anropar dataaccess-komponenten och sen använder managerklasser för att bygga om databärarna till entiteter och utför nödvändig logik?Sv: Tvålagerslösning
Sv:Tvålagerslösning
Men det är allså repositoryn som i mitt fall skulle ansvara för att bygga om datatables/datasets från datalagret till entiteter?Sv: Tvålagerslösning
Svar ja...
Men jag skulle nog inte använda DataSets utan Readers i första hand. Om jag ändå skall fylla eniteter finns det ingen anledning att köra med DataSet typen.
Address
- Street
- Number
...
Address address = AddressRepository.GetAddressByNumber(number);
AddressRepository
- GetAddressByNumber(int number)
...
Address address = new Address();
address.Street = reader["Street"].ToString();
address.Number = reader["Number"].ToString();
...
return ( address );
mvh JohanSv:Tvålagerslösning
Som det kodexemplet som du bifogade ser ut så använder du det precis som jag har gjort med mina "Managers". Det jag blev fundersam över i länken som Patrik bifogade är att den ju fungerar som en collection av objekt. Hur sköts det?Sv:Tvålagerslösning
Sv:Tvålagerslösning
address.Street = reader["Street"].ToString();
address.Number = reader["Number"].ToString();
(i stället skriver man bara in ett nytt fält i Dataset-designern..)
En annan fördel är att man får gratis stöd för att importera/exportera entiteterna som XML, osv.Sv: Tvålagerslösning
Sv:Tvålagerslösning
Sv: Tvålagerslösning
Men jag är fortfarande inte med på riktigt vad repositories innebär. Var någon som visade ett exempel där de såg ut ungefär som manager-klasser som jag har gjort tidigare men vad jag har läst mig till så är repository, som namnet antyder, en collection och det är jag lite osäker på hur det blir.
Går flödet från webbsidan till någon typ av handler som först pratar med en repository som hanterar logiken och sen datalagret?Sv:Tvålagerslösning
Sv: Tvålagerslösning
Hur brukar ni hantera det?Sv:Tvålagerslösning
SqlDataReader reader = cmdSelect.ExecuteReader(CommandBehaviour.CloseConnection);
reader.Close(); // Här stängs kopplingen ocksåSv:Tvålagerslösning
Först ang DataSet. Vist kan du använda DataSet hoppas nu du syftade på typat :-)
Annars kommer du inte alls undan kod där man måste skriva in kolumner för hand.
Men en DataSet är ottroligt stort och klumpigt att hantera i minnet, ok i .Net 2.0 har
de förbättrat dem men DataSet är typ inmemmory database dvs en relationsbaserad
struktur. En objekt model som Patrik syftar på som jag själv oxå bygger efter handlar mer
om Object Orientering och dess tankar. Dvs spegala affärsmodellen i OO och inte spegla
en relations databas som objekt modell.
Sedan kan man använda O/R Mappers för att slippa skriva mappningskoden själv och bara speca upp i en enkel XML-fil hur ens objekt skall mappas mot Databas.
NHibernate, nPersist är två rätt ok ramverk för detta. Inte så moget inom .net världen än men inom java har det existerat länge...
Sedan Readers, dessa skickar man inte upp till UI utan mappar helst om dem til lentiteter som man
sedan skickar upp i UI. Det handlar om att dela upp sin modell i minst 3 olika lager där alla lager
har sin lilla funktion. Affärslagret dvs objekt modellen speglar ens use case och så mkt verkligheten du kan komma. Den i sin tur måste tyvärr lagra sin info i databas för att man senare skall kunna återskapa den data man arbetat med detta gör datalgret. Ett datalager har i huvuduppgift att acessa datakällan läsa dess data sedan se till så dess data mappas och fyller upp de objekt man har i sin objekt modell. Sedan har man UI som använder sig av objekt modellen för att presentera datan eller
för att fylla datan från fomulär som man sedan läser av och trycker in i databasen.
Försök bygga din affärsmodell utan att tänka DATABAS låtsas att du inte har en databas att dina objekt och dess data alltid ligger i objekten i datorns minne... Tänker man så får man en bra modell. Sedan använder du DataBasen som en svart låda för tyvärr har inte en dator evigt minne eller ström någon gång måste den startas om etc...
Här är en liten väldigt enkel och grundläggande artikel som jag en gång skrev om att skapa sin domän modell från use case eller user storires.
http://www.pellesoft.se/area/articles/article.aspx?artid=872
Mvh JohanSv: Tvålagerslösning
När det gäller readers. Det klart man ska använda readers för att ta fram långa listor. Förutsatt att dina lager lever i samma process. Om t.ex. kunden vill ha 200 poster i en HTML-tabell på webben. Tänker du då skapa 200 business-entitet i RAM-minnet som sedan kastas bort - bara med syftet att skapa lite HTML-kod för en tabellrad? (då förstår jag varför du ville snåla på minnet.. men det är ju verkligen inte en optimal lösning.. :)Sv:Tvålagerslösning
Så är det bara för mig är DataSet inga bra objekt för en bra objekt modell med 100% OOP.
Det är fler onödiga objekt att hantera och en den chatty calls för att få fram ett värde ur ett DataSet.
Det jag gillar minst är att DataSet är relations databas i minnet typ. Värsta tänkbara då man helst skall undvika att tänka Databas och speciellt relations tänk i en OO miljö.
Allt handlar om smak och design. Jag gör mkt renare och effektivare och mer underhållsam kod när jag kör utan DataSets. Mindre tecken att skriva, renare kod, bättre koll på objektmodel och har endast de metoder en entitet etc kräver inte massa lull lull som DataSets har. Att skapa ett typad dataset tar ibland längre tid att skapa upp och få ordning på än skriva egna entiteter.
Men jag säger inte att ni inte skall använda DataSets detta är min erfarenhet och för mig har produktiviteten samt fel minimerats då koden blivit mer självbeskrivande gett mindre antal rader samt tecken kod att läsa vid felsökning m.m. Men vem vet kanske andra lyckats effektivisera sitt användande av DataSets. Jag gick från DataSets för att jag inte lyckades effektivisera mera, men detta var dock då 1.1 släpptes.
Mvh JohanSv: Tvålagerslösning
Både bra och dåligt då? =)Sv:Tvålagerslösning
menade ju att produktiviteten ökat och fel minimerats... :-) missade ordet bara.
bra noterat... (Skäms) :-/Sv: Tvålagerslösning
Nu returnerar jag datareaders till affärslagret men vad rekomenderar ni för databärare när en entitet ska sparas ner i databasen?
Ska jag flytta ut mina entiteter från affärslagret och låta både datalagret och affärslagret använda dem eller?
Funderade på om man kunde ha enkla structar i datalagret som affärslagret bygger från entiterna? Eller är det helt galet det?Sv:Tvålagerslösning
Du plockar dem från en factroy som nyttjar datalagret. Dvs har du en Article entitet så kan du ha en
ArticleRepository som har metoder som. Get och Save eller nått.
i Get skapar du en Article klass nyttjar Dphelper eller nått får en reader fyller Article stänger readern och använder article. När du sparar skickar du in Article köär du en SP så anger du bara parametrarna efter Areticles värden.
Pseudopkod:
....Parameter....("@Title"......). Value = article.Title;
Mvh JohanSv: Tvålagerslösning
Men då måste ju datalagret känna till entiteterna, som ligger i affärslagret.Sv:Tvålagerslösning
Återigen så får överliggande lager använda underliggande lager.
ArticleRepository.Save(Articel articel)
{
DpHelper dpHelper = New DbHelper();
Sqlparameters[] ....
....
... Sätt Paramter values ......
....
dpHelper.ExecuteNoQuery();
...
}
Lagerstruktur på detta är.
------------------------- BUS --------------------
Article
ArticleRepository
----------------------------------------------------
------------------------ DAL ----------------------
DbHepler
----------------------------------------------------
mvh JohanSv: Tvålagerslösning
------------------------- BUS --------------------
Class Artikel (motsvarar din repository klass)
Public DS As ArticleDataset (typat dataset)
Public Function Get()
Public Function Update()
' osv
End Class
----------------------------------------------------
------------------------ DAL ----------------------
Microsoft.ApplicationBlocks.Data.SqlHelper
----------------------------------------------------
Fördelarna:
1. slipper skriva entitetsklasser. VS genererar dom baserat på en XSD
som man skapar visuellt.
2. Tack vare SqlHelpern blir det väldigt lite kod
i Article Repositoryt. Den har ju möjligheten att extrahera
ut vilka sp-parametrar som ska användas i en sp
baserat på en Datarow (om parametrarna har samma namn)
Vi har alltså inte en enda Parameters.Add() rad i hela systemet.
Så t.ex.
<code>
'Uppdaterar en befintlig
Public Sub Update()
SqlHelper.ExecuteNonQueryTypedParams _
(Param.ConnStr, "KFArtikelUpd", DsArtikel.KFArtikel.Item(0))
End Sub
</code>
Det är alles.
Prestandamässigt blir detta bra, eftersom SqlHelper har en ParameterCache.
Vi valde detta att vi tyckte det var tillräckligt bra och vi var tidspressade.
Summa summarum, systemet funkar kalas och det är inga direkta problem med DS.
Nackdelar:
1. Om man får problem med Dataset/SqlHelper så kan det vara lurigt att hitta det.
Som tur är har vi inte haft så många sådana problem.
2. Dataset-koden som skapas är lite stor, men den är helt okey.
Att det skulle vara jobbigare att ändra tycker jag inte. Snarare tvärtom, jag behöver inte ens skriva nån kod om ett fält tillkommer (om man inte räknar med att det ska in nånstans i UI:t) Sv:Tvålagerslösning
Prova att använda en binärserialiserare för att spara den till disk, gör samma med motsvarande objektsmodell. Jag gjorde en presentation om performence på ÖreDev förra året, då var det en av mina demon. Skillnaden är mer än dubbelt, jag kommer inte ihåg exakta siffror dock men det är ganska mycket extra information.Sv:Tvålagerslösning
t.ex Johan skrev:
------------------------- BUS --------------------
Article
ArticleRepository
----------------------------------------------------
------------------------ DAL ----------------------
DbHepler
----------------------------------------------------
och Ola;
------------------------- BUS --------------------
Class Artikel (motsvarar din repository klass)
Public DS As ArticleDataset (typat dataset)
Public Function Get()
Public Function Update()
' osv
End Class
----------------------------------------------------
------------------------ DAL ----------------------
Microsoft.ApplicationBlocks.Data.SqlHelper
----------------------------------------------------
Dvs, båda skrev att Entiteterna och Repository-klasserna (även kallade DAL-komponenter) var i Business-lagret. Men enligt Microsoft på denna länk (som för övrigt anger vad Microsoft har att säga om precis detta problem som tråden tar upp) ligger båda dessa klasser i datalagret. (Spana in bilden nästan högst upp)
Designing Data Tier Components and Passing Data Through Tiers
http://msdn.microsoft.com/practices/apptype/webapps/default.aspx?pull=/library/en-us/dnbda/html/boagag.asp
Jag tycker det känns mer naturligt att DAL-komponenterna (repositories) borde tillhöra data-lagret då de är starkt kopplade till just datalagringen genom att man t.ex. anger SQL-parametrar och liknande?
Och när det gäller entiteterna har jag ibland sett att de lägger det som ett lager verticalt vid sidan om så alla lager kommer åt detta. Det är nog om man bara har data och inga t.ex CRUD-metoder. Men i artikeln finns ett alternativ där man har CRUD-metoder i entiteterna och också DAL-komponenterna i datalagret. Och det står då att det är okej att anropa datalagret direkt från presentationslagret i de fall man inte behöver någon affärslogik (så man slipper metoder som bara skickar vidare anrop).
Men då man har rejäla entiteter som innefattar mycket affärslogik och vill placera dessa i affärslagret vet jag inte riktigt hur det blir. Då det blir mer tveksamt om man kan skicka ner dessa objekt till DAL-komponenterna för att sparas ner osv.
Vad har ni för tankar kring detta?
(För övrigt står t.ex. för och nackdelar med dataset och object ganska utförligt i artikeln)Sv: Tvålagerslösning
MS bygger lite efter sina egna påhitt precis som många andra modeller, min modell härstammar från DDD (Domän Driven Design) där är lagerindelningen inte "lika" hård som MS. Dvs ArticleRepository är typ en factory som i sin tur gränsar mellan DAL och BUS om man skall vara mer petig. Lite svårt att rita upp detta i ett diagram av ASCII tecken.
Tanken med DDD och även med MS grej är att de hjälpklasser man använder för att hämta data lätt skall kunna bytas ut. i DDD är det domänen som är det viktigaste dvs det MS kallas BUS lagret.
Repositories är typ de enda klasser som kommer gå mot datalgret och dess datakälla så vill man byta ut dataaccess komponenter så går det väldigt smidigt och man kan behålla sina Repositories.
I en DDD modell ligger det egentligen inte nått direkt DAL heller utan man har SQLHelper, eller vad man nu använder i ett lager som alla lager delar som kallas Infrastructure ett bibliotek med hjälpklasser som
alla lager kan dra nytta av. Där Repositories som står närmst datakällan nyttjar SQLHelpern.
MS Business Enteties är rätt rena databärarobjekt vilket mina entiteter inte måste vara i en DDD modell, där innehåller dessa objekt affärsmetoder.
OBS! oxå att MS vet inte bäst bara för att de har en modell de gillar är inte det "THe Bible" of success. De har mkt att lära och smaken inom deras organisation är delad. Det hela handlar mer om vad man själv tycker bäst om och som fungerar bäst för just dig. Viktigt att skaffa egen åriskt egna idér sin smak och sin modell som effektiviserar just ditt arbete. MEN glöm inte du skriver oftast kod för andra ovh inte dig själv så ha tanken i bakuvudet kommer nästa person förstå min kod och min modell? Självbeskrivande modell och kod är viktigare än vilken modell man använder.
Så MS modell är en DDD är en annan det finns många fler. Smaka på dem, testa dem och se vad du gillar bäst, vad som blir snyggast i dina ögon, vilken modell dina kollegor tycker fungerar bäst, kanske du kan ta idéer från många modeller och göra din egna?
Mvh JohanSv:Tvålagerslösning
"Repositories är typ de enda klasser som kommer gå mot datalgret och dess datakälla så vill man byta ut dataaccess komponenter så går det väldigt smidigt och man kan behålla sina Repositories."
Det som jag inte förstår riktigt är hur du ska kunna behålla dina repositories när du går över till en XML-datakälla eftersom repositoriesarna verkar starkt kopplade till just relationsdatabaser? Tanken är väl att man endast ska byta datalagret om man byter datakälla?Sv: Tvålagerslösning
Beror på vad du har för klasser i din infrastruktur som sköter koppling mot datakälla.
Har du ett transparant ramverk så går det hur bra som helst. :-)Sv:Tvålagerslösning
om ditt dal är tillräckligt bra så märker inte klient kod som repositories att du byter från databas till XML. Men allvarligt, hur ofta händer det att du "byter" från databas till XML, eller från databas till ngt annat? Du bygger för en resource manager. om du bygger för att i framtiden kanske vill ändra, då försöker du vara ett orakel, man kan aldrig gissa vart ett system tar vägen om man inte har direkta krav.
Om kravet är databas då är kravet databas inte "databas men vi kanske vill ändra till xml i framtiden". Typsikt utvecklar beteende att gissa och förbereda för scenarion som kanske aldrid slår in.
En bra designer / arkitekt jobbar efter YAGNI ( YOu Aint Gonna Need It).Sv: Tvålagerslösning
Måste man i sådana fall ha en ytterligare abstraktion i kommunikationen mellan affärslagret och datalagret? Detta lär ju medföra mycket mer kod då man måste konvertera mellan de abstraktionsklasser man använder i datalagret för att slippa kopplingen till relationsdatabaser och de klasser man har i affärslagret som t.ex. Order, Kund osv?
Har jag förstått det hela rätt?Sv:Tvålagerslösning
Sv: Tvålagerslösning
Sv:Tvålagerslösning
Men det är fortfarande en grej som jag inte får ihop. Det har en koppling till andra tråden om O/R-mappning också.
1. Om det är så att Business-entiteterna ska vara i Business-lagret och man använder en O/R-mapper som genererar SQL-kod så måste ju denna O/R-mapper befinna sig i Datalagret då den genererar SQL. Samtidigt så är ju O/R-mapperns uppgift att skapa Business-entiteterna, men dessa ligger i Businesslagret och man ska ju inte ha en koppling upp i lagrena?
2. Och i det fallet man använder Data Application Block måste man ju skicka in SQL-kod också då DAB är baserat på det. Och då blir det SQL-kod i de repositories som finns i Business-lagret (enligt tidigare inlägg) vilket inte heller hör hemma i Business-lagret riktigt?
Hur går det här ihop med de olika lagrena och beroenden till SQL och Business-entiteterna?
//Jakob