Vad är portkartläggning? Teknik för datamigrering i stora projekt

Problem

Du har laddat ner en kostnadsredovisningsrapport och vill visa den för ledningen. För att göra detta måste du sammanställa artikeldata bokföring- enligt förvaltningsredovisningsposter. Du vet hur redovisnings- och redovisningsartiklar förhåller sig till varandra, men varje gång att förbereda en sådan rapport manuellt tar dig för mycket tid.

Lösning

Vi kommer att betrakta det här fallet som en fortsättning på det föregående. Låt oss föreställa oss att du skapade följande katalog i Excel:

Fig.2.1. Katalog: kartläggning av BU- och CU-artiklar


Till vänster finns en kostnadspost (AC), till höger en förvaltningsredovisningspost (MA). Det är viktigt att kostnadsposten endast visas en gång i den första kolumnen, annars fungerar inte mappningsmekanismen korrekt.

(Förresten, engelskt ord kartläggning översätts som visning eller korrespondens, så referensboken in I detta fall- detta är något allmän regel hur BU-artiklar återspeglas i OU-artiklar).

Fig.2.2. Platt tabell: kostnadsrapport (från "Kontoomsättning 20")


Observera att kolumnen "Artikel TC" har dykt upp i den sjunde kolumnen. Mittemot varje kostnadspost har vi placerat en förvaltningsredovisningspost. Detta kan göras manuellt, men det är mycket bekvämare att använda det här verktyget:

Fig.2.3. Platt tabell: kostnadsrapport (från "Kontoomsättning 20")


Längst ner på formuläret finns namnen på sidorna: "Hem" är en platt tabell som innehåller kostnadsdata (fig. 2.2), "spr" är en uppslagsbok (fig. 2.1).

Kolumnnumren anges överst i formuläret. Så, i det här fallet, om data i kolumn 1 i katalogen och 3 på huvudsidan sammanfaller, kopieras data från den andra kolumnen i katalogen till den 7:e kolumnen på huvudsidan.

Detta formulär har också många ytterligare alternativ. Du kan till exempel aktivera kryssrutorna "Funktion #2" och "Funktion #3" och sedan överföra data från kolumn 2 i katalogen till kolumn 7 på huvudsidan om katalogen och startsida Jag kommer att matcha två eller till och med tre detaljer samtidigt.

Som ett resultat av en så enkel operation, med hjälp av en pivottabell, kan du bygga hela raden olika analysrapporter, där ett av avsnitten kommer att innehålla analytikern ”Artikel UU”. Till exempel, så här:

Fig.2.4. Kostnadsrapport för armeringsverkstad


Jämförelse av kartläggning med VLOOKUP()

Många användare är bekanta med och använder funktionen VLOOKUP() i dessa typer av situationer. Funktionen VLOOKUP() fungerar dock bara bra på icke- stora volymer data, medan detta formulär klarar bra av att bearbeta Excel-tabeller, även om du har, säg, 5 000 rader i referensboken och 300 000 rader på goav-sidan. Försök att kontrollera det och du kommer att se att VLOOKUP() misslyckas vid sådana volymer. Dessutom skapar funktionen VLOOKUP() en betydande belastning på Excel, vilket tvingar den att utföra stora mängder beräkningar. Kartläggningsformuläret undviker denna nackdel: det körs en gång, varar i några sekunder (i stora volymer av minuter) och efter det finns det ingen extra belastning på Excel fil skapas inte längre.

I den här artikeln vill vi systematisera vår erfarenhet av att utföra datamigrering i stora företagsprojekt relaterade till övergången av kunder till arbete i 1C:Enterprise 8-konfigurationer.

Samtidigt kommer huvudvikten i artikeln först och främst att läggas på den tekniska komponenten i migrationsprocessen. Den organisatoriska delen påverkas också, men i mindre utsträckning.

Termer och definitioner

Datamigrering förstås vanligtvis som en slutlig arbetssekvens, ett projekt som syftar till en engångs massförflyttning av data från källsystem (historiska system) till destinationssystemet. Samtidigt upphör exploateringen av dessa data i källsystemen.

Datamigrering måste särskiljas från dataintegration. Integration, i motsats till migration, är permanent del IT-arkitektur, och ansvarar för flödet av data mellan olika system och datalager – och är en process, inte en projektaktivitet.

Migreringsschemat ser generellt ut så här:

Ris. 1

Historiska system- databaser över kundens företag, som planeras att helt eller delvis bytas ut vid implementering av ett nytt system.

Mottagare system- målsystem, godtycklig konfiguration "1C:Enterprise 8".

Inledande data- data som laddas ner från historiska system till ett anpassat xls-filformat. I det här fallet verkar xls-formatet vara ett av de mest bekväma, eftersom möjligheten att ladda upp till en xls-fil finns i många redovisningssystem av "tidigare generationer".

Hur modernt alternativ Det är möjligt att betrakta xml-filformatet som en transport.

Det finns också alternativ för att använda en mellanliggande databas.

Förvandling, omvandling- processen att konvertera källdata till data för laddning. Datatransformation sker i enlighet med laddningsmallar. Resultatet av transformationen är de data som ska laddas.

Data att ladda ner- data avsedda att laddas in i det mottagande systemet. Den här artikeln, liksom källdata, tar hänsyn till xls-formatet.

Datamallar för laddning- Beskrivning av datatabeller som ska laddas in i målsystemet.

Migrationsstadier

Låt oss överväga processen att förbereda och genomföra migrering steg för steg.

De organisatoriska stadierna av migration inkluderar följande punkter:

· Definiera en migrationsstrategi. I detta skede kommer entreprenören och beställaren överens om tekniken för att utföra migreringsarbeten;

· Fastställande av sammansättningen av migrationsarbetsgruppen. I arbetsgruppen bör ingå specialister från både entreprenören och beställaren som är tillräckligt förtrogna med driften av historiska system (på beställarens sida) och målsystemet (på entreprenörens sida);

· Preliminär migrationsplan. Migrationsplanen kommer att justeras flera gånger allt eftersom projektet fortskrider;

· Perioder av datum för nedladdning av data från historiska system, datavolymer. Data cut-off perioder för migrering, datum för test och slutliga migrationer. Denna informationen kan hänföras till migrationsplanen;

· Sammansättning av data som ska migreras. Referensdata, klassificerare, transaktionsdata, saldon, omsättning, etc.;

· Frågor om kontroll av datas kvalitet, korrekthet och integritet under migreringsprocessen och i slutet;

· Återställningsproblem tidigare tillstånd vid misslyckanden.

Låt oss uppehålla oss mer i detalj vid migrationens tekniska stadier.

Ris. 2

1.Förbereda mallar för dataladdning

Dataladdningsmallen innehåller tekniska beskrivningar datatabeller för laddning, algoritmer och laddningsregler för den aktuella mallen.

Varje mall riktar sig i allmänhet mot en eller flera relaterade tabeller på målmålsystemet.

Mallen säger:

· Beskrivning av alla fält i xls-datafilen för nedladdning, inklusive:

o Fältnamn

o Indikator på att fältet måste fyllas i

o Exempel på att fylla i fältet

o Obs

· Beskrivning av reglerna för att ladda målsystemtabellen baserat på de data som ska laddas (kö vid flera relaterade tabeller, sökalgoritmer för nyckelfält, etc.)

· Beskrivning av att fylla i fälten i målsystemtabellerna direkt om något annat än att överföra data "en till en" från en datafil för laddning tillhandahålls. Relevant för till exempel referensfält.

Under arbetet i detta skede ska Entreprenören även förbereda en datafilladdare för laddning. När du arbetar med xls-filer är denna uppgift inte särskilt svår.

2.Identifiering av datakällor

Detta steg kan börja tillsammans med föregående steg "1. Förbereder mallar för dataladdning."

I detta skede avgör kundens specialister från vilka system och vilken data som kan laddas ner. Du bör också bestämma vilken data Kanske kan behövas.

Vanligtvis kan det i stora migreringsprojekt ta ganska lång tid att identifiera en komplett, omfattande lista över datakällor. länge sedan och inträffar när arbetet fortskrider i efterföljande etapper.

Det finns ofta situationer då, för att ytterligare säkerställa informationens integritet, vissa data måste överföras från tryckta källor (digitaliseras) eller till och med matas in i tabeller enligt orden från kundens nyckelmedarbetare.

Men i detta skede bör du försöka identifiera så mycket nödvändig information som möjligt.

3. Ladda upp källdata

Processen att ladda ner data från historiska system kan ta ganska lång tid, speciellt om det finns många system, de är olika och olika indelningar av kunden är ansvariga för dem. Denna punkt måste beaktas under test och slutlig migrering.

Det mest bekväma alternativet verkar vara att ladda upp till xls-filer. Många äldre IT-system stödjer detta alternativ.

Det kan också finnas alternativ för uppladdning till csv-format, dbf, xml-format och andra.

Det är värt att notera att av en eller annan anledning (säkerhetsproblem, till exempel), kan kunden inte alltid tillhandahålla datanedladdningar i sin helhet i detta skede! Bara en datastruktur och några testpositioner. Det kan alltså uppstå en situation att under test- och slutladdningar kommer data av låg kvalitet att upptäckas i källtabellerna, vilket leder till oplanerade fel.

För att minimera detta problem bör volymen testnedladdningar från historiska system överenskommas i förväg.

4.Datamappning

Kartläggning (datamapping) - i allmänhet processen att jämföra data från historiska system och det mottagande systemet. Det vill säga källdata och data som ska laddas.

Kartläggningsskedet är det mest arbetsintensiva skedet och kan ta upp mer än 50 % av allt arbete med migrationsuppgiften.

I detta skede, alla arbetsgrupp migrationsprojekt.

I processen för datakartläggning är det nödvändigt att skilja på delstadierna av tabellkartläggning och fältkartläggning.

· Kartläggning av tabeller, eller kartläggning av mallar - jämförelse av tabeller med källdata och datamallar för laddning. Matchen kan vara antingen 1:1 eller N:N. Som ett resultat av detta arbete kompileras och underhålls ett tabellmappningsregister. Detta delsteg är nödvändigt för nästa delsteg av fältkartläggning och för att övervaka det övergripande tillståndet för kartläggning.

Grupp av 1C-mallar

Namn på 1C-mallen

Filnamn-

källa

Regler för att skapa en källfil

Ansvarig

Status

Notera

NSI

Prov_

Nomenklatur

Nomenk

latura.xls

Ställ in val i system N
. Spara till txt
. Öppna i xls, kolumner är text
. Den första raden är rubriken
. Antal kolumner - 15
. Kontrollera antalet rader i txt och xls
. Arknamnet är alltid "Sheet1"

Ivanov I.I.

på jobbet

· Fältmappning - mappning av tabellfält inom ramen för en redan definierad tabellmappning. Resultatet av detta arbete är ett fältkarteringsregister.

№pp

Cl. fält

Nödvändig

1C mallfältnamn "Template_Nomenclature"

Beskrivning

Fältnamn "Nomenclature.xls"

Fyllningsalgoritm

Koda

Katalogelementkod

Koda

namn

namn

Ja

Denna grupp

Innehåller ett av värdena:
. 1 - för grupper
. 0 - för element

Om kodens längd=11 tecken och de sista 4 tecknen<>"0000", då är detta element "0", annars är gruppen "1".

Fullständiga namn

Katalogelementnamn

namn

Om ThisGroup = 1, Då "", ElseIf ThisGroup = 0, sedan Namn.

Som en del av detta skede bör du också utföra möjliga verk om datanormalisering.

5.Förbereda omvandlingsregler

Till skillnad från de tidigare stegen är detta steg tekniskt och involverar entreprenörsutvecklarens arbete.

Utifrån de överenskomna fältkarteringsregistren utvecklar Entreprenörens specialister regler för datatransformation.

För operativt arbete under de förberedande stadierna av migreringen och vidare, under test- och slutmigreringarna, är det viktigt att det finns en bekväm miljö för att utveckla regler (skript) för datatransformation och en miljö för att konvertera källdata till data för laddning.

Kraven för denna miljö inkluderar:

· Bekvämlighet och snabb utveckling av omvandlingsregler;

· Datakonverteringshastighet. In- och utdatafilerna kan vara hundratusentals rader långa!

· Förmåga att arbeta med flera indatafiler samtidigt;

· Möjlighet att spara transformationsregler i separata filer.

För våra migreringsprojekt har vi utvecklat en specialiserad arbetsstation för utvecklare, baserad på standardbehandling"Frågekonsol" 1C.

Query Console-behandlingen har förbättrats för att tillåta direkta frågor till xls-filer.

Här är ett exempel på att kombinera två xls-källfiler Anställda.xls


Anställningskod

Efternamn

namn

Efternamn

Födelsedatum

2423

Ivanov

Ivan

Ivanovich

17.11.1992

1523

Petrov

Basilika

Aleksandrovich

04.02.1991

4363

Sidorov

Kirill

Nikolajevitj

01.05.1995

Denisov

Denis

Denisovich

01.01.1990

Och Operationer.xls med sidor:

Avskrivningar

Anställningskod

datum

Belopp

2423

01.02.2014

1523

02.02.2014

4363

03.02.2014

04.02.2014

100000

2423

05.02.2014

1523

06.02.2014

4363

07.02.2014

2356

08.02.2014

140000

2423

09.02.2014

1523

10.02.2014

4363

11.02.2014

23523

12.02.2014

80000

Och Kvitton:

Anställningskod

datum

Belopp

01.05.2004

02.05.2004

03.05.2004

04.05.2004

2423Födelsedatum

Kvittobelopp

Avskrivet belopp

Ivanov Ivan Ivanovich

2423

17.11.1992

1341234

1010

Petrov Vasily Alexandrovich

1523

04.02.1991

245245

Denisov Denis Denisovich

01.01.1990

380000

320000

Sidorov Kirill Nikolaevich

4363

01.05.1995

613382

26336

TOTAL:

2579861

347842

Observera att exemplet är artificiellt, speciellt utvalt för att visa alla möjliga stadier av transformation av datakällor.

Den tekniska sekvensen av transformationsoperationer här är som följer:

Använda Access SQL frågespråk (som ger betydande ytterligare egenskaper, jämfört med 1C-frågespråket), skapas en första fråga som hämtar data från xls filen på onsdag 1C. Samtidigt är olika kontroller och normalisering av data möjliga redan i detta skede.

ADO dataåtkomstteknik ger hög hastighet arbete.

Ris. 3

2. Fråga på 1C-språk - huvudfrågan som implementerar fältmappningsalgoritmen. Och även: berikning av nedladdade data med data från 1C-databasen, omgruppering, sammanslagning med resultaten av frågor till andra xls-källfiler, etc.

3. Efterbearbetning av 1C-förfrågningsresultatet vid behov. Implementerat med ett skript i 1C-språk.

Till exempel implementerar vi här tillägget av "TOTAL"-raden i beloppskolumnerna.

4.Skriv den slutliga datamängden till en xls-fil.

I allmänhet får vi vid utgången de slutliga filerna för att laddas in i målbas 1C data.

Också detta verktyg låter dig spara datakonverteringsregler i en separat xml-fil:

Dessutom går det att arbeta V batch-läge , vilket är särskilt viktigt när det finns en stor mängd heterogen migrerande data.

Under de tidigare stegen avslutas i allmänhet den förberedande delen av arbetet - alla datakällor identifieras, källdata laddas ner från källorna, nedladdningsmallar förbereds i måldatabasen, datakartläggning förbereds och slutligen utvecklas datatransformationsskript. .

Det bör noteras att innan den slutliga migreringen bör du definitivt utföra flera tester. Under testmigreringar identifierar entreprenören tillsammans med kunderna:

Konverteringsfel, dataladdningsfel

· utföra preliminär bedömning kvaliteten på data som laddas in i målsystemet

Baserat på resultaten av testmigreringar skapar/uppdaterar de en slutlig migreringsplan

7.Dataavstämning

Kvaliteten på den nedladdade datan bör kontrolleras både efter testmigrering och i slutet av den slutliga migreringen. Under avstämningen kan följande indikatorer kontrolleras:

· Tändstickor totala belopp enligt saldon, enligt dokument;

· Kvantitativa matchningar, till exempel antalet OS;

· Korrekt fyllning av enskilda utvalda enheter;

Observera att vissa kontroller av migrerande data och problem med datanormalisering måste lösas under alla migreringsprocesser. Du måste alltid fråga dig själv vad som behöver göras i det aktuella skedet för att undvika misstag i efterföljande etapper.

Till exempel:

· Kontrollera om det finns dubbletter av nyckelfält. Det kan och bör utföras på originaldata;

· Tvång av fälttyper;

· Referensintegritet;

· Matematiska inkonsekvenser. Till exempel, kontrollera om det finns tomma numeriska fält i vilka uppdelning planeras under transformation;

· I allmänhet fylls kontroll av obligatoriska fält i;

· Ersättning av felaktiga tecken. Till exempel engelska tecken i kyrilliska fält ("o", "a", "e", etc.) Detta gäller särskilt för nyckelfält!

· Kontrollera värdena för strängfält för överensstämmelse med typerna av det mottagande systemet (längdbegränsningar)

Efter att den slutliga migreringen är klar, enligt en förutbestämd migrationsstrategi och migrationsplan, fattas beslut om den fortsatta driften av de historiska systemen.

Ofta slutförs operationen omedelbart efter de slutliga dataavstämningarna och registreringen av migreringens framgång - användare av det nya systemet för inte längre register i två system parallellt, utan byter helt till det nya systemet. Samtidigt tillgång till gammalt system sparas i läsläge.

I vissa fall kan parallelldrift av två system förekomma under provdriftens varaktighet (TE) och även efter denna period. Frågan om parallellt arbete av användare i två system är nära relaterat till frågan om möjligheten att återgå till det gamla systemet om migreringen (eller generellt sett driften av det nya systemet!) anses otillfredsställande.

Slutsats

Avslutningsvis vill jag notera att när det gäller att migrera stora transaktionssystem, som inkluderar många 1C:Enterprise-konfigurationer, kan övergången till ett nytt system vara mycket arbetskrävande.

Därför bör man komma ihåg att ett sådant projekt kräver noggrann förberedelse och måste åtföljas av en individuell plan. Men oavsett vilken typ av system som migreras, databasvolymer osv. allmän ordning migrationen ser nästan identisk ut.


I föregående del tittade vi på typerna av relationer (en-till-en, en-till-många, många-till-många), samt en klassbok och dess kartläggningsklass BookMap. I den andra delen kommer vi att uppdatera klassen Bok, skapa de återstående klasserna och kopplingar mellan dem, som avbildades i föregående kapitel i databasdiagrammet ovanför underrubrik 1.3.1 Relationer.

Kod för klasser och mappningar (Med kommentarer)

Klassbok

Public class Book ( //Unik identifierare public virtual int Id ( get; set; ) // Titel public virtual string Namn ( get; set; ) // Beskrivning public virtual string Beskrivning ( get; set; ) // Rating of the World of Fiction public virtual int MfRaiting ( get; set; ) //Sidnummer public virtual int PageNumber ( get; set; ) //Länk till bilden offentlig virtuell sträng Bild (get; set; ) //Datum för bokens ankomst (filter av nya objekt!) public virtual DateTime IncomeDate ( get; set; ) //Genre (Many-to-Many) //Varför ISet och inte IList Endast en samling (IList) kan väljas med JOIN-hämtning, om mer än en? samling behövs för JOIN-hämtning, då är det bättre att konvertera dem till en ISet offentlig virtuell ISet-samling Genrer ( get; set; ) //Serier (Många-till-en) offentliga virtuella Serier ( get; set; ) //Opinion och andra (En-till-en) privat Sinne _mind; public virtual Mind Mind ( get ( return _mind ?? (_mind = new Mind()); ) set ( _mind = value; ) ) //Author (Many-to-many) public virtual ISet Författare ( get; set; ) //Initiera i förväg så att ett noll-undantag inte inträffar. public Book() ( //Oordnad uppsättning (en tabell kan inte ha två exakt identiska rader, annars väljer den en och ignorerar den andra) Genres = new HashSet (); Författare = nytt HashSet (); ) ) //Mapping class Boka offentlig klass BookMap: ClassMap ( public BookMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); Map(x => x.MfRaiting); Map(x = > x.PageNumber); Map(x => x.Image) Map(x => x.IncomeDate); //ManyToMany(x => x.Genres) objektet sparas, uppdateras eller tas bort, alla beroende objekt kontrolleras och //created/updated/added.Cascade.SaveUpdate() //Namnet på den mellanliggande tabellen MÅSTE vara detsamma som klassen Genre .Table("Book_Genre" ); > x.Autors) .Cascade.SaveUpdate() .Table("Book_Author"); . => x.Mind).Cascade.All().Constrained();

Offentlig klass Författare ( offentlig virtuell int Id ( get; set; ) //Namn-Efternamn offentlig virtuell sträng Namn ( get; set; ) //Biografi offentlig virtuell sträng Biografi ( get; set; ) //Böcker offentlig virtuell ISet Böcker ( get; set; ) //Initializing Authors public Author() ( Books=new HashSet (); ) ) // Author Mapping public class AuthorMap: ClassMap ( public AuthorMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.Biography); //Många-till-många relation HasManyToMany(x => x .Books) //Cascade-regler Alla - När ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till.Cascade.All() //Ägaren av samlingen är den andra änden av relationen (Bok) och den kommer att sparas först .Inverse() //Namnet på mellantabellen MÅSTE vara detsamma som bokklassen.

Klass Genre

Public class Genre ( public virtual int Id ( get; set; ) //Namn på genren offentlig virtuell sträng Namn (get; set; ) //Engelska namnet på genren offentlig virtuell sträng EngName (get; set; ) //Böcker offentlig virtuell ISet Böcker ( get; set; ) //Initialize books public Genre() ( Books=new HashSet (); ) ) //Genre mapning public class GenreMap: ClassMap ( public GenreMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.EngName); //Many-to-many relation HasManyToMany(x => x .Books) //Cascade-regler Alla - När ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till.Cascade.All() //Ägaren av samlingen är den andra änden av relationen (Bok) och den kommer att sparas först .Inverse() //Namnet på mellantabellen MÅSTE vara detsamma som bokklassen.

Klassens åsikter:

Public class Mind ( public virtual int Id ( get; set; ) //My opinion public virtual string MyMind ( get; set; ) //Fantlabs åsikt public virtual string MindFantLab ( get; set; ) //Book public virtual Book Book ( get; set; ) ) //Mapping public class MindMap:ClassMap ( public MindMap() ( Id(x => x.Id); Map(x => x.MyMind); Map(x => x.MindFantLab); //En-till-en relation HasOne(x => x .Bok ); ) )

Klasscykel (serie):

Public class Series ( public virtual int Id ( get; set; ) public virtual string Name ( get; set; ) //Jag skapade en IList, inte en ISet, för förutom boken är Series inte associerad med något annat, även om du kan göra och ISställa offentlig virtuell IList Böcker ( get; set; ) //Initialisering av böcker. public Series() ( Böcker = ny lista (); ) ) public class SeriesMap: ClassMap ( public SeriesMap() ( Id(x => x.Id); Map(x => x.Name); //En-till-många relation HasMany(x => x.Books) ////Ägare av samlingen i den andra änden av relationen (bok) och den sparas först.

En liten förklaring
offentlig virtuell ISet Genrer(get;set;)
offentlig virtuell ISet Författare ( get; set; )

Varför ISet , och inte till exempel den IList som många känner till ? Om vi ​​använder IList istället för ISet och försöker köra projektet kommer vi inte att märka någon större skillnad (tabeller och klasser kommer att skapas). Men när vi lägger till tabellerna Genre och Authors till klassen Book LeftJoin samtidigt och vi försöker visa icke-repeterande poster från boktabellen (Distinct Book.Id) i en vy (View), kommer Nhibernate att kasta en undantag och ett fel.
Kan inte hämta flera väskor samtidigt.
I sådana fall använder vi ISet, särskilt eftersom set är avsedda för detta (de ignorerar dubbletter av poster).

Många-till-många relation.

NHibernate har konceptet med ett "huvudbord". Även om många-till-många-relationen mellan bok- och författaretabellerna är likvärdig (En författare kan ha många böcker, en bok kan ha många författare), kräver Nhibernate att programmeraren anger tabellen som lagras som andra (har en metod. invers). ()), det vill säga först kommer en post att skapas/uppdateras/ta bort i boktabellen, och först sedan i tabellen författare.
Cascade.All innebär att utföra kaskadoperationer på spara-uppdatering och radering. Det vill säga när ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till (Ps. Kan skrivas istället för Cascade.All -> .Cascade.SaveUpdate().Cascade.Delete())
Method.Table("Book_Author"); skapar en "mellanliggande" tabell "Book_Author" i databasen.

Många-till-en, en-till-många relation.

Metoden.Constrained() säger till NHibernate att en post från Book-tabellen måste matcha en post från Mind-tabellen (ID:t för Mind-tabellen måste vara lika med ID:t för Book-tabellen)

Om du nu kör projektet och tittar på Bibilioteca-databasen kommer nya tabeller med redan bildade kopplingar att dyka upp.

Fyll sedan de skapade tabellerna med data...
För att göra detta kommer vi att skapa en testapplikation som sparar data i databasen, uppdaterar och raderar den, ändrar HomeController enligt följande (vi kommenterar onödiga delar av koden):
public ActionResult Index() ( med (ISession session = NHibernateHelper.OpenSession()) ( med (ITTransaction transaktion = session.BeginTransaction()) ( //Create, add var createBook = new Book(); createBook.Name = "Metro2033" ; createBook.Description = "Post-apokalyptisk mystik"; createBook.Authors.Add (Namn = "Glukhovsky"); (Namn = "Metro"); createBook.Mind = new Mind (MyMind = "Post-apokalyptisk mystik"); (1); //var updateBook = session.Get (1); //updateBook.Name = "Metro2034"; //updateBook.Description = "Dystopi"; //updateBook.Authors.ElementAt(0).Name = "Glukhovsky"; //updateBook.Genres.ElementAt(0).Name = "Dystopi"; //updateBook.Series = serie; //updateBook.Mind.MyMind = "11111"; //session.SaveOrUpdate(updateBook); //Delete (Med ID) //var deleteBook = session.Get

En liten förklaring

  1. (1); () //session.Delete(deleteBook); transaktion.Commit(); ) Genre genreAl = null; Författare författareAl = null; Serie serieAl = noll; Mind mindAl = null; var böcker = session.QueryOver;
  2. () //Left Join with table Genres .JoinAlias(p => p.Genres, () => .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p .Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //Ta bort dubbletter av tabell-id-nummer Book.TransformUsing(Transformers.DistinctRootEntity). (); return View(books); var böcker = session.QueryOver
    Välj * Från bok
    .JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin)
    - liknande att köra ett SQL-skript:
  3. .TransformUsing(Transformers.DistinctRootEntity)- Liknar att köra ett SQL-skript: VÄLJ distinkt bok.Id..., (tar bort dubblettposter med samma id)

Typer av föreningar
() //Left Join with table Genres .JoinAlias(p => p.Genres, () => .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p .Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //Ta bort dubbletter av tabell-id-nummer Book.TransformUsing(Transformers.DistinctRootEntity). (); return View(books);

  1. LeftOuterJoin - väljer alla poster från den vänstra tabellen ( bok), och lägger sedan till rätt tabellposter till dem ( Genre). Om en motsvarande post inte hittas i den högra tabellen visas den som Null
  2. RightOuterJoin är motsatsen till LEFT JOIN - den väljer alla poster från den högra tabellen ( Genre), och lägger sedan till de vänstra tabellposterna till dem ( bok)
  3. InnerJoin - väljer bara de poster från de vänstra tabellerna ( bok) som har en motsvarande post från den högra tabellen ( Genre), och förenar dem sedan med poster från den högra tabellen

Låt oss ändra representationen enligt följande:

Indexvy

@modell IEnumerable @( Layout = null; ) Index

@Html.ActionLink("Skapa nytt", "Skapa")

@foreach (var artikel i modell) ( @(string strSeries = item.Series != null ? item.Series.Name: null;) }
@Html.DisplayNameFor(modell => modell.namn) @Html.DisplayNameFor(model => model.Mind) @Html.DisplayNameFor(modell => modell.Series) @Html.DisplayNameFor(modell => modell.Författare) @Html.DisplayNameFor(modell => modell.Genres) Operationer
@Html.DisplayFor(modelItem => item.Name) @Html.DisplayFor(modelItem => item.Mind.MyMind)@Html.DisplayFor(modelItem => strSeries) @foreach (var författare i item.Authors) ( sträng strAuthor = författare != null ? författare.Namn: null; @Html.DisplayFor(modelItem => strAuthor)
}
@foreach (var genre i item.Genres) ( sträng strGenre = genre!= null ? genre.Name: null; @Html.DisplayFor(modelItem => strGenre)
}
@Html.ActionLink("Redigera", "Redigera", ny ( id = item.Id )) | @Html.ActionLink("Detaljer", "Detaljer", ny ( id = artikel.Id )) | @Html.ActionLink("Radera", "Ta bort", ny ( id = artikel.Id ))




Efter att ha kontrollerat alla operationer en efter en kommer vi att märka att:
  • Under Skapa och uppdatera operationerna uppdateras all data som är kopplad till boktabellen (ta bort Cascade="save-update" eller cascade="all" och associerade data kommer inte att sparas)
  • Vid radering raderas data från tabellerna Book, Mind, Book_Author, men återstående data raderas inte eftersom de har Cascade="save-update"

Kartläggning för klasser som har arv.
Hur kartlägger man klasser som har arv? Låt oss säga att vi har det här exemplet:
//Klass av tvådimensionella former public class TwoDShape ( //Width public virtual int Width ( get; set; ) // Höjd public virtual int Height ( get; set; ) ) // Class Triangle public class Triangel: TwoDShape ( / /Identifieringsnummer public virtual int Id ( get; set; ) //Typ av triangel offentlig virtuell sträng Style ( get; set; ) )

I princip är det inget komplicerat i denna mappning, vi kommer helt enkelt att skapa en mappning för den härledda klassen, det vill säga triangeltabellen.
//Triangelmapping offentlig klass TriangleMap: ClassMap ( public TriangleMap() ( Id(x => x.Id); Map(x => x.Style); Map(x => x.Height); Map(x => x.Width); ) )
Efter att ha startat programmet kommer följande (tomma) tabell att dyka upp i Biblioteca-databasen

Taggar:

  • asp.net mvc 4
  • övervintra
  • sql-server
Lägg till taggar

Portkartläggning- detta är omdirigering av mottagna data på ett sådant sätt att data som tas emot på någon port på en dator automatiskt omdirigeras till någon annan port på en annan dator.

Faktum är att detta är mycket lättare att tekniskt implementera än att förklara själva principen. Detta kan jämföras med en solstråle: om du riktar en ljusstråle in i en spegel reflekteras den "automatiskt" och lyser upp ett föremål. Dessutom, om du belyser en person och den här personen inte vet att strålen reflekterades från spegeln, kommer han att tro att ljuset kommer från platsen där spegeln är belägen. Det är samma sak här: all data du överför överförs utan förvrängning till en annan dator, som kan placeras var som helst.

Denna teknik påminner lite om en proxyserver, men den är mycket enklare och mycket mindre flexibel.

Schemat är ungefär detsamma som när du använder en proxy (man kan säga att portmappning liknar en proxy - men detta kommer att vara samma sak som att säga "farfar är som ett barnbarn" - i själva verket liknar en proxy portmappning ):

Din dator >>> dator med portmappning >>> fjärrserver.

Varför behöver du portmappning?

  1. Om din organisation använder en företagsproxy kan du använda portmappningen på den till en extern e-postserver (mail.ru) några e-postprogram från företagets nätverk - och du behöver inte installera/konfigurera några ytterligare program!
  2. På exakt samma sätt som ett e-postprogram kan du konfigurera nästan vilket annat program som helst! Om den bara stödde TCP/IP.

Naturligtvis är dessa bara de viktigaste sätten att använda portkartläggning. Det finns många andra typer av aktiviteter där det också kommer att vara väldigt, väldigt användbart.

Fördelar med hamnkartläggning

  1. Detta system är väldigt enkelt och det finns många program på Internet som låter dig implementera denna funktion;
  2. Eftersom data överförs till 100 % utan någon förvrängning, garanteras du 100 % anonymitet;
  3. Om du använder det här systemet behöver du inga "soxifiers" - eftersom ingen ytterligare anslutningsinitiering krävs, är anslutning till en portmappare likvärdig med att ansluta till en fjärrdator.

Nackdelar med hamnkartläggning

  1. Detta system är inte flexibelt. Till skillnad från en proxy, där du kan ansluta till många webbplatser via en proxy, kan du ansluta via en portmappning till endast en server.
  2. För varje ny portmappning måste du ändra inställningarna på servern där denna funktion är implementerad - detta är inte tillgängligt från klientdatorn.
  3. På internet Nej gratis portmappare (på grund av deras extrema begränsningar - en portmappning ger tillgång till endast en server), så om du vill vara riktigt anonym på din dator måste du ha en server någonstans där ett portmappningsprogram kommer att installeras - och nu kommer adressen till denna server att "lysa" i webbplatsloggarna.

Hur man arbetar med portkartläggning

Observera att schemat för att arbeta med portmappning är ungefär detsamma som när man arbetar med en proxy, bara ännu enklare. Portmappning är ett alias (extra namn) för den dator som den är konfigurerad på.

Låt oss anta att portmappning är gjord:

192.168.1.255:1234 => www.mail.ru:80 (port 80 är porten webbservrar)

Sedan, för att öppna webbplatsen mail.ru, kan du använda två metoder - öppna webbplatsen i ett webbläsarfönster:

  1. http://www.mail.ru
  2. http://192.168.1.255:1234/
    (i det här fallet, se till att skriva http://)

Jag skulle vilja notera: om du behöver använd portmappning, då du ska bara använda den andra adressen. Det vill säga, om du inte kan ansluta till mail.ru, bör du bara använda den interna adressen (http://192.168.1.255:1234/).

Portmappning på lokal dator

I fallet när du gör portmappning på din egen dator anger du vanligtvis:

  1. lokal hamn - lokal hamn på din dator som du måste ansluta till för att använda portmappning. Detta nummer kan vara vad som helst (från 1 till 65535), helst mer än 1000;
  2. fjärrvärd - den datorn (värd), på vilken anger portmappning. Detta kan till exempel vara e-postservern pop.mail.ru;
  3. fjärrport - datorport, till vilken Anslutningen sker via portmappning. För att ta emot e-post (POP3) är detta vanligtvis port 110, för att skicka e-post (SMTP) - port 25, för webbservrar (www...) - detta är vanligtvis port 80.

Så i det här fallet behöver du (genom att ställa in portmappning) ansluta Inte till mail.ru (och liknande), och ange din egen dator som server:

127.0.0.1:lokal hamn

där lokalhamnen ligger portnummer, som anges vid konfigurering av portmappning. Detta kan till exempel vara port 1234.

Det vill säga, om du gjorde portmappning på en webbplats, måste du skriva: http://127.0.0.1:1234/

Om du ställer in e-post, då som Mejl server Vänligen ange 127.0.0.1 - både för att ta emot och skicka post. Och glöm inte att hitta portnummerinställningarna (POP3 och SMTP) i din e-postklient och ändra dem i enlighet med dina inställningar i portmappning!


Del 3: Visa data från en tabell (LIST Operation)

I föregående del tittade vi på typerna av relationer (en-till-en, en-till-många, många-till-många), samt en klassbok och dess kartläggningsklass BookMap. I den andra delen kommer vi att uppdatera klassen Bok, skapa de återstående klasserna och kopplingar mellan dem, som avbildades i föregående kapitel i databasdiagrammet ovanför underrubrik 1.3.1 Relationer.

Kod för klasser och mappningar (Med kommentarer)

Klassbok

Public class Book ( //Unik identifierare public virtual int Id ( get; set; ) // Titel public virtual string Namn ( get; set; ) // Beskrivning public virtual string Beskrivning ( get; set; ) // Rating of the World of Fiction public virtual int MfRaiting ( get; set; ) //Sidnummer public virtual int PageNumber ( get; set; ) //Länk till bilden offentlig virtuell sträng Bild (get; set; ) //Datum för bokens ankomst (filter av nya objekt!) public virtual DateTime IncomeDate ( get; set; ) //Genre (Many-to-Many) //Varför ISet och inte IList Endast en samling (IList) kan väljas med JOIN-hämtning, om mer än en? samling behövs för JOIN-hämtning, då är det bättre att konvertera dem till en ISet offentlig virtuell ISet-samling Genrer ( get; set; ) //Serier (Många-till-en) offentliga virtuella Serier ( get; set; ) //Opinion och andra (En-till-en) privat Sinne _mind; public virtual Mind Mind ( get ( return _mind ?? (_mind = new Mind()); ) set ( _mind = value; ) ) //Author (Many-to-many) public virtual ISet Författare ( get; set; ) //Initiera i förväg så att ett noll-undantag inte inträffar. public Book() ( //Oordnad uppsättning (en tabell kan inte innehålla två exakt identiska linjer, annars väljer den ena och ignorerar den andra) Genres = new HashSet (); Författare = nytt HashSet (); ) ) //Mapping class Boka offentlig klass BookMap: ClassMap ( public BookMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.Description); Map(x => x.MfRaiting); Map(x = > x.PageNumber); Map(x => x.Image) Map(x => x.IncomeDate); //ManyToMany(x => x.Genres) objektet sparas, uppdateras eller tas bort, alla beroende objekt kontrolleras och //created/updated/added.Cascade.SaveUpdate() //Namnet på den mellanliggande tabellen MÅSTE vara detsamma som klassen Genre .Table("Book_Genre" ); > x.Autors) .Cascade.SaveUpdate() .Table("Book_Author"); . => x.Mind).Cascade.All().Constrained();

Offentlig klass Författare ( offentlig virtuell int Id ( get; set; ) //Namn-Efternamn offentlig virtuell sträng Namn ( get; set; ) //Biografi offentlig virtuell sträng Biografi ( get; set; ) //Böcker offentlig virtuell ISet Böcker ( get; set; ) //Initializing Authors public Author() ( Books=new HashSet (); ) ) // Author Mapping public class AuthorMap: ClassMap ( public AuthorMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.Biography); //Många-till-många relation HasManyToMany(x => x .Books) //Cascade-regler Alla - När ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till.Cascade.All() //Ägaren av samlingen är den andra änden av relationen (Bok) och den kommer att sparas först .Inverse() //Namnet på mellantabellen MÅSTE vara detsamma som bokklassen.

Klass Genre

Public class Genre ( public virtual int Id ( get; set; ) //Genre name public virtual string Namn ( get; set; ) // engelskt namn genre offentlig virtuell sträng EngName ( get; set; ) //Books public virtual ISet Böcker ( get; set; ) //Initialize books public Genre() ( Books=new HashSet (); ) ) //Genre mapning public class GenreMap: ClassMap ( public GenreMap() ( Id(x => x.Id); Map(x => x.Name); Map(x => x.EngName); //Many-to-many relation HasManyToMany(x => x .Books) //Cascade-regler Alla - När ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till.Cascade.All() //Ägaren av samlingen är den andra änden av relationen (Bok) och den kommer att sparas först .Inverse() //Namnet på mellantabellen MÅSTE vara detsamma som bokklassen.

Klassens åsikter:

Public class Mind ( public virtual int Id ( get; set; ) //My opinion public virtual string MyMind ( get; set; ) //Fantlabs åsikt public virtual string MindFantLab ( get; set; ) //Book public virtual Book Book ( get; set; ) ) //Mapping public class MindMap:ClassMap ( public MindMap() ( Id(x => x.Id); Map(x => x.MyMind); Map(x => x.MindFantLab); //En-till-en relation HasOne(x => x .Bok ); ) )

Klasscykel (serie):

Public class Series ( public virtual int Id ( get; set; ) public virtual string Name ( get; set; ) //Jag skapade en IList, inte en ISet, för förutom boken är Series inte associerad med något annat, även om du kan göra och ISställa offentlig virtuell IList Böcker ( get; set; ) //Initialisering av böcker. public Series() ( Böcker = ny lista (); ) ) public class SeriesMap: ClassMap ( public SeriesMap() ( Id(x => x.Id); Map(x => x.Name); //En-till-många relation HasMany(x => x.Books) ////Ägare av samlingen i den andra änden av relationen (bok) och den sparas först.

En liten förklaring
offentlig virtuell ISet Genrer(get;set;)
offentlig virtuell ISet Författare ( get; set; )

Varför ISet , och inte till exempel den IList som många känner till ? Om vi ​​använder IList istället för ISet och försöker köra projektet kommer vi inte att märka någon större skillnad (tabeller och klasser kommer att skapas). Men när vi lägger till tabellerna Genre och Authors till klassen Book LeftJoin samtidigt och vi försöker visa icke-repeterande poster från boktabellen (Distinct Book.Id) i en vy (View), kommer Nhibernate att kasta en undantag och ett fel.
Kan inte hämta flera väskor samtidigt.
I sådana fall använder vi ISet, särskilt eftersom set är avsedda för detta (de ignorerar dubbletter av poster).

Många-till-många relation.

NHibernate har konceptet med ett "huvudbord". Även om många-till-många-relationen mellan bok- och författaretabellerna är likvärdig (En författare kan ha många böcker, en bok kan ha många författare), kräver Nhibernate att programmeraren anger tabellen som lagras som andra (har en metod. invers). ()), det vill säga först kommer en post att skapas/uppdateras/ta bort i boktabellen, och först sedan i tabellen författare.
Cascade.All innebär att utföra kaskadoperationer på spara-uppdatering och radering. Det vill säga när ett objekt sparas, uppdateras eller tas bort kontrolleras alla beroende objekt och skapas/uppdateras/läggs till (Ps. Kan skrivas istället för Cascade.All -> .Cascade.SaveUpdate().Cascade.Delete())
Method.Table("Book_Author"); skapar en "mellanliggande" tabell "Book_Author" i databasen.

Många-till-en, en-till-många relation.

Metoden.Constrained() säger till NHibernate att en post från Book-tabellen måste matcha en post från Mind-tabellen (ID:t för Mind-tabellen måste vara lika med ID:t för Book-tabellen)

Om du nu kör projektet och tittar på Bibilioteca-databasen kommer nya tabeller med redan bildade kopplingar att dyka upp.

Fyll sedan de skapade tabellerna med data...
För att göra detta kommer vi att skapa en testapplikation som sparar data i databasen, uppdaterar och raderar den, ändrar HomeController enligt följande (vi kommenterar onödiga delar av koden):
public ActionResult Index() ( med (ISession session = NHibernateHelper.OpenSession()) ( med (ITTransaction transaktion = session.BeginTransaction()) ( //Create, add var createBook = new Book(); createBook.Name = "Metro2033" ; createBook.Description = "Post-apokalyptisk mystik"; createBook.Authors.Add (Namn = "Glukhovsky"); (Namn = "Metro"); createBook.Mind = new Mind (MyMind = "Post-apokalyptisk mystik"); (1); //var updateBook = session.Get (1); //session.Delete(deleteBook); transaktion.Commit(); ) Genre genreAl = null; Författare författareAl = null; Serie serieAl = noll; Sinne sinne //updateBook.Name = "Metro2034"; //updateBook.Description = "Dystopi"; //updateBook.Authors.ElementAt(0).Name = "Glukhovsky"; //updateBook.Genres.ElementAt(0).Name = "Dystopi"; //updateBook.Series = serie; //updateBook.Mind.MyMind = "11111"; //session.SaveOrUpdate(updateBook); //Delete (Med ID) //var deleteBook = session.Get

En liten förklaring

  1. (1); () //session.Delete(deleteBook); transaktion.Commit(); ) Genre genreAl = null; Författare författareAl = null; Serie serieAl = noll; Mind mindAl = null; var böcker = session.QueryOver;
  2. () //Left Join with table Genres .JoinAlias(p => p.Genres, () => .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p .Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //Ta bort dubbletter av tabell-id-nummer Book.TransformUsing(Transformers.DistinctRootEntity). (); return View(books); var böcker = session.QueryOver
    Välj * Från bok
    .JoinAlias(p => p.Genres, () => genreAl, JoinType.LeftOuterJoin)
    - liknande att köra ett SQL-skript:
  3. .TransformUsing(Transformers.DistinctRootEntity)- Liknar att köra ett SQL-skript: VÄLJ distinkt bok.Id..., (tar bort dubblettposter med samma id)

Typer av föreningar
() //Left Join with table Genres .JoinAlias(p => p.Genres, () => .JoinAlias(p => p.Authors, () => authorAl, JoinType.LeftOuterJoin) .JoinAlias(p => p .Series, () => seriesAl, JoinType.LeftOuterJoin) .JoinAlias(p => p.Mind, () => mindAl, JoinType.LeftOuterJoin) //Ta bort dubbletter av tabell-id-nummer Book.TransformUsing(Transformers.DistinctRootEntity). (); return View(books);

  1. LeftOuterJoin - väljer alla poster från den vänstra tabellen ( bok), och lägger sedan till rätt tabellposter till dem ( Genre). Om en motsvarande post inte hittas i den högra tabellen visas den som Null
  2. RightOuterJoin är motsatsen till LEFT JOIN - den väljer alla poster från den högra tabellen ( Genre), och lägger sedan till de vänstra tabellposterna till dem ( bok)
  3. InnerJoin - väljer bara de poster från de vänstra tabellerna ( bok) som har en motsvarande post från den högra tabellen ( Genre), och förenar dem sedan med poster från den högra tabellen

Låt oss ändra representationen enligt följande:

Indexvy

@modell IEnumerable @( Layout = null; ) Index

@Html.ActionLink("Skapa nytt", "Skapa")

@foreach (var artikel i modell) ( @(string strSeries = item.Series != null ? item.Series.Name: null;) }
@Html.DisplayNameFor(modell => modell.namn) @Html.DisplayNameFor(model => model.Mind) @Html.DisplayNameFor(modell => modell.Series) @Html.DisplayNameFor(modell => modell.Författare) @Html.DisplayNameFor(modell => modell.Genres) Operationer
@Html.DisplayFor(modelItem => item.Name) @Html.DisplayFor(modelItem => item.Mind.MyMind)@Html.DisplayFor(modelItem => strSeries) @foreach (var författare i item.Authors) ( sträng strAuthor = författare != null ? författare.Namn: null; @Html.DisplayFor(modelItem => strAuthor)
}
@foreach (var genre i item.Genres) ( sträng strGenre = genre!= null ? genre.Name: null; @Html.DisplayFor(modelItem => strGenre)
}
@Html.ActionLink("Redigera", "Redigera", ny ( id = item.Id )) | @Html.ActionLink("Detaljer", "Detaljer", ny ( id = artikel.Id )) | @Html.ActionLink("Radera", "Ta bort", ny ( id = artikel.Id ))




Efter att ha kontrollerat alla operationer en efter en kommer vi att märka att:
  • Under Skapa och uppdatera operationerna uppdateras all data som är kopplad till boktabellen (ta bort Cascade="save-update" eller cascade="all" och associerade data kommer inte att sparas)
  • Vid radering raderas data från tabellerna Book, Mind, Book_Author, men återstående data raderas inte eftersom de har Cascade="save-update"

Kartläggning för klasser som har arv.
Hur kartlägger man klasser som har arv? Låt oss säga att vi har det här exemplet:
Al = noll; var böcker = session.QueryOver //Klass av tvådimensionella former public class TwoDShape ( //Width public virtual int Width ( get; set; ) // Height public virtual int Height ( get; set; ) ) // Class Triangle public class Triangle: TwoDShape ( / / Ett identifikationsnummer

I princip är det inget komplicerat i denna mappning, vi kommer helt enkelt att skapa en mappning för den härledda klassen, det vill säga triangeltabellen.
//Triangelmapping offentlig klass TriangleMap: ClassMap ( public TriangleMap() ( Id(x => x.Id); Map(x => x.Style); Map(x => x.Height); Map(x => x.Width); ) )
Efter att ha startat programmet kommer följande (tomma) tabell att dyka upp i Biblioteca-databasen

public virtual int Id ( get; set; ) //Typ av triangel offentlig virtuell sträng Style ( get; set; ) )