by Benjamin Day Benjamin Day Consulting Inc About the speaker Owner Benjamin Day Consulting Inc Email bendaybendaycom Web httpwwwbendaycom Blog httpblogbendaycom Trainer ID: 430836
Download Presentation The PPT/PDF document "Object-Relational Mapping in the Microso..." is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
Object-Relational Mapping in the Microsoft World
by Benjamin DayBenjamin Day Consulting, Inc.Slide2
About the speaker
Owner, Benjamin Day Consulting, Inc.Email:
benday@benday.com
Web:
http://www.benday.comBlog: http://blog.benday.comTrainerVisual Studio Team System, Team Foundation ServerMicrosoft MVP for C#Microsoft VSTS/TFS Customer Advisory CouncilLeader of Beantown.NET INETA User GroupSlide3
Agenda
Overview of “the problem”Brief discussion of the optionsLINQ to SQLNHibernateEntity FrameworkSlide4
The PROBLEMSlide5
The Problem
Mismatch between objects and relational databasesObjects = inheritance, polymorphism, compositionDatabase = rows of data with relationships to other rows of dataSlide6
One Table Per Class
The class looks like the tableGreat candidate for a typed datasetSimple
Works nicely with DataAdapter because of RowStateSlide7
Limitations of Typed Dataset Route
Tight coupling with the databaseInheritance is difficultHow do you validate data?Null, data type, and length check validation is handled
Serious validation lives outside of the dataset
not very object-oriented
The ‘object’ route is better for validationValidation goes in the “set” propertySlide8
Object - DataRow Hybrid
Every object wraps a typed DataRowProperties control access to columns on the DataRow Facilitates more complex validationDataRow becomes a data transfer objectStill works nicely for System.Data integrationSlide9
Primitive Obsession
Validation in the get / set properties is ok but is phone number validation really the responsibility of the Person class? James Shore’s “Primitive Obsession”Too many plain scalar valuesPhone number isn’t really just a string
http://www.jamesshore.com/Blog/Slide10
Coarse-Grained vs. Fine-Grained Object Model
Fine-grained = More object-orientedData and properties are split into actual responsibilities
coarse-grained
fine-grainedSlide11
But how do you save it?
Four classes go to one table?Five instances go to one table?Slide12
Inheritance, Collections, and Relationships
Employee is a PersonEmployee has UnderlingsEmployee has a SupervisorSlide13
Limitations of Object - DataRow Hybrid
Inheritance >1 DataRow at onceOne for base class, one for descendent
Which instance of DataSet is the object using?
Complicates saves
Client has to worry about the internal state of the objectHow to save parent-child relationships? Employee has FK to a Supervisor Supervisor needs to be saved firstObjects have ability to modify internal state of other objects wrapping the same DataSet bugs & encapsulationNumber of records in the DataSet tends to grow rather than shrink
How to clear out old, unused records in the DataSet? How do you know when they’re old? Slide14
Object-Only Model
No more DataRowsClasses are member variables, methods and propertiesClean “Domain Model” patternBusiness tier worries about itselfDecoupled from the databaseStraightforward inheritance, polymorphismSlide15
Complications in the Object-Only Model
Data access (“Mapper”) tier has to “adapt” data and structures from the database into populated business objects and vice versaHow to manage IsDirty for INSERT vs UPDATE? Adding IsDirty logic to domain objects is a violation of the “separation of concerns”
Concurrency management?
Transaction management?Slide16
Do you really want to solve these problems?
Problems are solvableEverybody writes their own solutionPersistence is a distraction from solving The Real Business ProblemSlide17
Available OptionsSlide18
Options
LINQ to SQLEntity FrameworkNHibernateWilson OR Mapper
LLBLGen
And more…Slide19
LINQ to SQL
Available in Visual Studio 2008“Better typed dataset”Slide20
LINQ to SQL: Pros / Cons
ProsYou don’t have to write data access codeGood for Rapid Application Prototyping
Integrated into Visual Studio
Designer support
Will generate the database schema for youConsSQL Server onlyLimited inheritance modeling (Table Per Hierarchy only)Closely tied to the databaseUnusual way of handling stored procedures
Generates codeSlide21
Entity Framework
Microsoft’s first, real ORM solution(well…I guess this depends on who you talk to)In betaRumored to be released with Visual Studio 2008 sp1Slide22
Entity Framework: Pros / Cons
Pros
Full-featured
Not open source
Integrated into Visual StudioDesigner support (eventually)Support for non-SQL Server databases (eventually)Supports LINQSupport Table-per-TypeCons
Still in beta
Not open source
Version 1Slide23
NHibernate
Full-featured ORM solutionOpen sourceBased on Java’s Hibernate frameworkUses XML to map tables/columns to objects/propertiesSlide24
NHibernate: Pros / Cons
ProsRich selection of mappings
Inheritance
modelling
Polymorphic queriesEstablished solution with lots of current usersSupport for multiple database vendorsOpen sourceFreeConsOpen sourceFree
Not from Microsoft
3
rd
party library
Limited to zero GUI support
Currently doesn’t support LINQ
…but does have HQLSlide25
LINQ to SQLSlide26
Using the LINQ to SQL O/R Designer
Define classesSet up inheritanceSlide27
LINQ to SQL vs. Typed DataSets
My $0.02 – LINQ to SQL is the new Typed DataSetSlide28
LINQ to SQL vs. LINQ to DataSets
DataSets in VS2008 are query-able with LINQDataTable’s object model has changed
DataTable
now extends from
TypeTableBase<T>TypedTableBase<T> extends DataTableBackwards compatibleNo special way to fill the DataSet/DataTable with LINQ to SQL
Still uses
DataAdapterSlide29
LINQ to SQL vs. Raw SQL Access
Hopefully you don’t do this…The data access strategy of masochists everywhereSlide30
LINQ to SQL vs. NHibernate
NHibernate is LINQ to SQL’s older, more successful cousin
5+ years in .NET & Java
Full-featured ORM framework
Maps tables/columns to classes/propertiesUses xml mapping files or attributesComprehensive inheritance modelingHas LINQ-like object query syntax HQL – Hibernate Query LanguageMulti-vendor database support
Oracle,
SQLServer
(2000 & 2005),
MySql
, Sybase, etc
Lets you focus on the business problem rather than persistenceSlide31
Using LINQ to SQL with Unit Tests
When testing database code, database must be in a known stateEasiest way:Wipe the database between testsDataContext.DeleteDatabase()DataContext.CreateDatabase()
Database schema always in sync with code
Harder way:
Unit test manages transactionRollback at end of unit testSlide32
LINQ to SQL in an n-tier Application
Common BaseClassHooking into save eventsAuto-updating: ModifiedDate, ModifiedByKeeping your code organized with the “Service Layer” patternSlide33
Common Business Base Class
Each business class should probably have similar fieldsIdModifiedDate, ModifiedByCreateDate, CreatedByBummer: LINQ to SQL isn’t great at this
(NHibernate does this effortlessly)
Mapped columns must be defined on the concreteSlide34
Code Demo
Introduce a common business base classSlide35
Code Demo
Implement the partials and auto-populate the base class propertiesSlide36
Auto-update base class propertiesfrom
DataContextGenerated DataContext & other objects are partial classesGenerated code gives you partial methods on DataContext for each object
InsertXxx(), UpdateXxx(), DeleteXxx()
Create your own partial class and create your own implementation of the method
Don’t forget to call ExecuteDynamicInsert(), ExecuteDynamicUpdate() or ExecuteDynamicDelete()Slide37
Other fun stuff with the partial methods
Your partial implementations wipe out the LINQ to SQL default implementation(Who cares? This is boring.)You could put your own implementation that uses stored procedures in your partials!Slide38
Service Layer Pattern
From “Patterns Of Enterprise Application Architecture”
by Martin Fowler, Randy Stafford, et al.
Chapter 9
“Defines an application’s boundary with a layer of services that establishes a set of available operations and coordinates the application’s response in each operation.”
-Randy StaffordSlide39
Why Service Layer?
Formally defines supported business tier operations (aka methods)Methods provide ideal target for unit testingKeeps code organizedCode review: anything complex not in the service layer
refactor
Keeps code out of the UI
Isolates the Domain Model (business) objectsMinimize usage of the Domain Model objects outside of the Business tierSlide40
Service Layer in LINQ?
CRUD operations for each business object Any specialized “get” operationsCentralized place for any custom from-where-select’sFactory methods
Create a
BusinessFacade
<T>Slide41
Entity FrameworkSlide42
Entity Framework Overview
Still in betaOfficial release with VS2008 sp1Trying to be more than just an ORM3 layers
Conceptual Model (classes)
Storage / Logical Model (table definitions)
Mapping layer Slide43
NHibernateSlide44
What NHibernate
isn’t“Hibernate” has nothing to do with Windows HibernateNot object serializationNot a code generatorSlide45
NHibernate To The Rescue
.NET port of the Java-based Hibernate Object-Relational FrameworkNHibernate 1.2 is (roughly) Hibernate
2.1 + some features of Hibernate 3.0
“
Hibernate's goal is to relieve the developer from 95 percent of common data persistence related programming tasks.”Facilitates saves and retrieves of objects“Hibernate provides transparent persistence, the only requirement for a persistent class is a no-argument constructor.”Keeps your objects cleanOpen-source, free software under LGPL
http://www.jboss.org/opensource/lgpl/faq
Ported by Tom Barrett, Mike
Doerfler
, Peter
Smulovics
, and Sergey
KoshcheyevSlide46
What is it?
Object Relational Mapping FrameworkXML-basedMapping files *.hbm.xml
Classes/Properties
Tables/Columns1+ mapping fileshibernate.cfg.xmlDatabase Dialect: SQL Server, Oracle, MySQL, etc.Which assemblies to manageWhich mapping files to useSlide47
What it will do for you.
Make your life easierSimplify your data accessAllow you to focus on your business tierSlide48
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8" ?><hibernate-configuration xmlns="urn:nhibernate-configuration-2.0" >
<session-factory name="NHibernate.Test">
<!–- Writes all SQL to Console
--> <property name="show_sql">true</property> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<!–- SQL SERVER
-->
<property name="connection.connection_string"
>Server=localhost\sql2005;initial catalog=bugs;User ID=sa;Password=sa_password;Min Pool
Size=2</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name="connection.driver_class“
>NHibernate.Driver.SqlClientDriver</property>
<!-- mapped assemblies -->
<mapping assembly="NHibernateResearch.Business" />
</session-factory>
</hibernate-configuration>Slide49
Mapping files (*.hbm.xml)
<?xml version="1.0" encoding="utf-8" ?><
hibernate-mapping
xmlns="urn:nhibernate-mapping-2.0">
<class name="NHibernateResearch.Business.Person, NHibernateResearch.Business"
table="Person"
>
<
id
name="PersonId" type="System.Int32" unsaved-value="0">
<generator class="native" />
</id>
<timestamp name="LastModified" />
<
property
name="FirstName" not-null="true"></property>
<property name="LastName" not-null="true"></property>
</class>
</hibernate-mapping>Slide50
<class>
Simplest mappingMaps a class to a database tableAttributes“name” = name of the persistent class
Fully qualified class name, assembly name (no “.dll”)
“table” = name of the table
Required element<id> = defines object identityCommon elements<timestamp>, <version> for optimistic concurrency<property> for mapping class properties to database columnsSlide51
<id>
<id name="PersonId" type="System.Int32" unsaved-value="0"> <generator class="native" />
</id>
Required element of <class> mapping
Used to establish object identity, database primary keyAttributes“name” – name of the property “column” – (optional) name of the table column
“type” – (optional) data type for the property
“unsaved-value” – used to determine INSERT vs. UPDATE
For “identity” columns, specify a <generator>
class=“native” uses int identity column (SQL Server) or sequence (Oracle)
class=“guid” generates guid keys
For non-”identity” columns use <composite-id>
This approach is strongly discouragedSlide52
<property>
<property name="LastName" not-null="true"></property>
<property name="
Html
"> <column name="HtmlContent" sql-type="text" not-null="true"></column></property>
Child element to <class>
Used to map a property to a database column
Attributes
“name” – name of the property
“column” – (optional) name of the database column
“not-null” – (optional) describes the nullability of the database column
defaults to nullable
“type” – (optional) datatype for the property
Optional <column> element describes information about the database column
“sql-type” attribute – override default column datatype
“length” attribute – override default column lengthSlide53
Mapping the Person class
<class
name="NHibernateResearch.Business.Person, NHibernateResearch.Business"
table="Person">
<id name="PersonId" type="System.Int32" unsaved-value="0"> <generator class="native" /> </id>
<property name="FirstName" not-null="true"></property>
<property name="LastName" not-null="true"></property>
<property name="Email" not-null="true"></property>
<property name="HomePhone" not-null="true"></property>
<property name="WorkPhone" not-null="true"></property>
</class>Slide54
The NHibernate Session
Main point of contactISession interfaceSessionFactory.OpenSession() Objects are associated the ISessionLazy loadingSave, delete, and retrieve operationsSlide55
Saving
SaveUpdate() Person person1 = new Person(); // create
person1.Name.FirstName = "firstname1";
// set properties
person1.Name.LastName = "lastname1";session.SaveOrUpdate(person1);session.Flush();session.Close();Slide56
Transactions
Call BeginTransaction() on the sessionpublic virtual void Save(object item)
{
ITransaction tx = null;
try { tx = m_session.BeginTransaction();
m_session.SaveOrUpdate(item);
tx.Commit();
}
catch (Exception ex)
{
if (tx != null) tx.Rollback();
throw ex;
}
}Slide57
Retrieving
Query / HQL syntaxHQL = Hibernate Query LanguageSQL-like queries against the object model Use for more complex queries (JOINs)Criteria syntaxBuild the query programmatically
NHibernate Allows Polymorphic QueryingSlide58
HQL Sample
Find Employees by Supervisor’s NameSlide59
HQL Sample
public IList FindSupervisorEmployees(
string firstName, string lastName)
{
string hqlQ
uery =
@"
from Person p
where p.Supervisor.FirstName = :firstName
and
p.Supervisor.LastName = :lastName";
IQuery query = Session.CreateQuery(
hqlQ
uery);
query.SetParameter("
firstName
",
firstName
);
query.SetParameter("
lastName
",
lastName
);
return query.List();
}Slide60
ICriteria: Load All By Type
Gets an IList of objects by type or interfacepublic IList GetList(
Type type
)
{ ICriteria criteria = m_session.CreateCriteria(type); return criteria.List();
}
Polymorphic queries
Piano : MusicalInstrument
Flute : MusicalInstrument
CreateCriteria(typeof(MusicalInstrument))
Returns mix of Piano and Flute objectsSlide61
ICriteria: Load By Property Value
Gets a list of objects by type where a property has a certain value
public
IList
Get(Type type, string propertyName, object propertyValue){
ICriteria criteria =
m_session.CreateCriteria(type);
crit
eria
.Add(Expression.Eq(propertyName, propertyValue));
IList list = crit
eria
.List();
return list;
}Slide62
Deleting
Session.Delete(object instance)Slide63
Making Person More Fine-grained
coarse-grained
fine-grained
fine-grainedSlide64
Mapping Fine-grained PersonSlide65
<component>
<component name="Name" class="NHibernateResearch.Business.Name, NHibernate
Research
.Business">
<property name="FirstName" not-null="true"></property> <property name="LastName" not-null="true"></property></component>Used to map columns in a table to properties on a different classObject does not have it’s own “identity”No primary key, no <id>
Only exists in relation to the containing class
Cannot save an instance of “Name” by itself to the databaseSlide66
Mapping Person Using <component>
<class name="NHibernateResearch
.Business.Person, NHibernateResearch.Business" table="Person">
<id name="PersonId" unsaved-value="0">
<generator class="native" /> </id> <component name="Name" class="NHibernateResearch.Business.Name, NHibernateResearch.Business"> <property name="FirstName" not-null="true"></property>
<property name="LastName" not-null="true"></property>
</component>
<component name="Email" class="NHibernateResearch.Business.Email, NHibernateResearch.Business">
<property name="Address" column="EmailAddress" not-null="true"></property>
</component>
<component name="WorkPhone" class="NHibernateResearch.Business.Phone, NHibernateResearch.Business">
<property name="Number" column="WorkPhone" not-null="true"></property>
</component>
<component name="HomePhone" class="NHibernateResearch.Business.Phone, NHibernateResearch.Business">
<property name="Number" column="HomePhone" not-null="true"></property>
</component>
</class>Slide67
Concurrency Columns
Child elements of <class>Must be declared immediately after the <id><timestamp> – uses date/time data to manage concurrency<version> – uses a numeric version idSlide68
Mapping Inheritance
Employee is a PersonSlide69
<joined-subclass>
<class name="NHibernateResearch.Business.Person, NHibernateResearch.Business" table="Person"> <id name="PersonId" unsaved-value="0">
<generator class="native" />
</id>
... <joined-subclass name="NHibernateResearch.Business.Employee, NHibernateResearch.Business" table="Employee"> <key column="EmployeeId"/>
<property name="Title" not-null="true" />
<many-to-one name="Supervisor" column="SupervisorId" not-null="false" cascade="save-update"></many-to-one>
<bag name="Underlings" lazy="true" inverse="true" cascade="save-update">
<key column="SupervisorId"></key>
<one-to-many
class="NHibernateResearch.Business.Employee, NHibernateResearch.Business"
></one-to-many>
</bag>
</joined-subclass>
</class>
Subclass gets its own table for its properties/columns
<joined-subclass> element goes inside of the superclass’ <class> or <joined-subclass> element
<key> element defines the name of the column to use to join from the superclass’ <id> (Person.PersonId
Employee.EmployeeId)Slide70
Mapping Associations & Collections
Supervisor is an EmployeeEmployee has UnderlingsSlide71
Associations
Associations define relationships between classesNHibernate uses the association mappings to automatically store and retrieve related objects<one-to-one> – file has one owner
<one-to-many> – directory has many files
<many-to-one> – sub-directory has one parent directory (many sub-directories, one parent)
<many-to-many> – Many users, many roles intersection of a user and a roleSlide72
<many-to-one>, <one-to-many>
<joined-subclass name="NHibernateResearch.Business.Employee, NHibernateResearch.Business" table="Employee">
<key column="EmployeeId"/>
<property name="Title" not-null="true" />
<many-to-one name="Supervisor" column="SupervisorId" not-null="false" cascade="save-update”></many-to-one>
<bag name="Underlings" lazy="true" inverse="true" cascade="save-update">
<key column="SupervisorId"></key>
<one-to-many
class="NHibernateResearch.Business.Employee, NHibernateResearch.Business“
/>
</bag>
</joined-subclass>
SupervisorId is a foreign-key to the supervisor’s EmployeeId
Many-to-one turns the SupervisorId into an instance of Employee
not-null=“false” means that the SupervisorId is nullable
cascade=“save-update” tells NHibernate to check the many-to-one relationship for changes when an INSERT or UPDATE is requested
The association syntax is also used to populate collections of objects
<bag> populates an IList of Employee objects for the current employee
select * from employee where supervisorId=@currentEmployeeIdSlide73
Collections
Mapping Element
Interface
Implementation
Description
<list>
IList
ArrayList
Ordered collection
<bag>
IList
ArrayList
Unordered collection, allows duplicates
<map>
IDictionary
Hashtable
Dictionary (key/value pairs)
Use associations to store collections of reference types
<one-to-many>, <many-to-many>
Use <element> tag to store collections of value types
Similar syntax to <property>Slide74
Collections: <bag>
Collection of objects
<bag name="Children" lazy="true" cascade="all">
<key column="ParentId"></key>
<one-to-many class="classname"></one-to-many></bag>Collection of values
<bag name="Children" lazy="true" cascade="all">
<key column="ParentId"></key>
<element column=“
columnName
“ type="System.Int32"/>
</bag>
System.Collections.IList
If collection of values, allows duplicates
If collection of objects, duplicates get eaten
By default, items in the collection
same order as they in the tables
“order-by” attribute available to do database sorts on dataSlide75
Collections: <list>
<list name="Children" lazy="true" cascade="all">
<key column="ParentId"></key>
<index column="indexValue"></index> <one-to-many class=“classname
" ></one-to-many>
</list>
System.Collections.IList
Uses an numeric, zero-based index column for sorting
Missing index values become null
child0.Index = 0;
// no child with Index of 1
child1.Index = 2;
parent.Children.Add(child0);
parent.Children.Add(child1);
session.Save(parent);
// reload the parent
parent.Children[0]
child0;
parent.Children[1] null;
parent.Children[2] child1;Slide76
Collections: <map>
<map name="Children" cascade="all"> <key column="ParentId"></key>
<index column="indexval" type="System.Int32"></index>
<one-to-many class="
classname" /></map>System.Collections.IDictionary
Unsorted collection uses Hashtable
Collection of key/value pairs
Use <index> for a value type key
Use <index-many-to-many> for an object key
<index-many-to-many column="ItemId"
class="
classname
" />
If sorted, collection uses SortedList
“order-by” attribute available to do database sorts on data
“sort” attribute for sorting using an implementation of IComparerSlide77
Collections
Lazy loading lazy = “true”Expose collections interface not concrete class
ArrayList
IList
Hashtable IDictionaryLazy-load proxy loads on first access“inverse” attribute for bi-directionality“child” has a reference back to the parentEmployee has SupervisorSupervisor has Employees“cascade” attributeSlide78
The “cascade” attribute
Controls when changes to child objects are savedOptions:“none” – no cascading saves/deletes“save-update” – cascade for INSERTs and UPDATEs“delete” – cascade on DELETEs only
“all” – cascade on INSERT, UPDATE, DELETE
“all-delete-orphan” – same as all, automatically delete any child objects when the parent’s collectionSlide79
NHibernate, Collections, and Generics
Current release is NHibernate 1.2.1Now supports genericsSlide80
Nullable Columns & ValueTypes
Nullable columns should be avoided even if you don’t use NHibernateSometimes you need themSometimes you’re stuck with them (legacy databases)Under .NET 2.0 – Use the “?” syntax for the nullable properties on your classesSlide81
Auditing Info
Auditing info common to all tables / classesCreateDate, CreatedByLastModified, LastModifiedByBase class functionalityHow to know when to update the values?Slide82
ILifecycle
Allows class to perform actions at certain times during the NHibernate “lifecycle” of the instanceOnSave(), OnUpdate
(),
OnDelete
(), OnLoad()Slightly “pollutes” object model with NHibernate specific codeNow is deprecated IInterceptorSlide83
Code Demo
Refactor Person to extend BusinessBaseImplement auditing on PersonSlide84
Intellisense for NHibernate
Eliminate the tediumEliminate the potential errorsLearn what else is in there
Download the source
Schemas in “src\NHibernate”
nhibernate-configuration-2.0.xsdnhibernate-mapping-2.0.xsdnhibernate-generic.xsdCopy to Visual Studio’s “Schemas” directory“c:\program files\Microsoft Visual Studio 8\Xml\Schemas”Restart Visual StudioSlide85
Contains(), Evict(), Lock(), Refresh()
Methods on NHibernate SessionContains(object) – Queries the session to determine if it is managing the supplied objectIs the object persistent for the session
Evict(object) – Remove an object from the session’s control
Lock(object, LockMode) – Request that the object becomes persistent for the session
Refresh(object) – Update the object with the current data from the databaseSlide86
“assembly” & “namespace”
Attributes on <hibernate-mapping>Specifies default
Assembly name
Namespace
This name="Com.Benday.ContentManagement.Business.DomainModel.Folder, Com.Benday.ContentManagement.Business” name=“Folder”Slide87
Simplify Data Access With Generics
Persistent objects operations are almost identicalISession Save(), Get(), Delete()ICriteria
GetBy***()
Leads to code duplication in your façade (aka Factory, Finder, Data Access) classes
Use .NET 2.0 generics to SimplifyGain compile-time type safetySlide88
Code Walkthrough
Com.Benday.NHibernateBusinessFacade<>Slide89
Mapping: <query>
Allows you to write HQL complex queries and store it separately from the code Assigned a unique nameAccessed through ISession.GetNamedQuery()
Executed via IQuery.List()Slide90
Mapping: <sql-query>
Write SQL queries against the native databaseStill brings back persistent objectsISession.GetNamedQuery(), IQuery.List()
<return class=“
classname
” alias=“table alias” />Table alias must be in “{ }”Slide91
Design Strategies
Model to schemaCreate the object model first, then create mappingsHave NHibernate generate the database schema
Allows you to be much more database independent
Concentrate on creating a good object model and less about storage
This is the best to start learning NHibernate-Write some code, write some mappings -Export the schema through NHibernate-Look at the database tables and FK relationships and see if it’s what you expectedSchema to modelDatabase first, then classes, then mappingsLegacy development
More difficult, more about the needs of the database and less focus on the object modelSlide92
Create Database Using SchemaExport
NHibernate.Tool.hbm2ddl namespaceReads hbm’s and classes creates database schema
Reads the database dialect
generates for your db (MySql, Sql Server, Oracle, etc etc) public static void ExportSchema(){ Configuration config = new Configuration();
config.Configure();
SchemaExport exporter = new SchemaExport(config);
exporter.Drop(true, true);
exporter.Create(true, true);
}
Great for unit testing
always have a clean db
db model always in sync with the hbm’sSlide93
Code Demo
Use BusinessFacade<> Use schema export from unit testsCreate an fixture base classCreate a
PersonFixture
Create a Person class
Play around with [TestInitialize] & [TestCleanup]Slide94
Mappings: Create a UNIQUE database constraint
“unique-key” attribute on the <column> mappingSet the same value on all properties that should participate in the keySlide95
Benjamin Day
Consultant, TrainerArchitecture, Development, Project CoachingMicrosoft VSTS Customer Advisory CouncilMVP for C#
Leader of
Beantown
.NET User GroupVSLive, O’Reilly ConferencesTeam System, Team Foundation Server, NHibernate, C#, ASP.NET, TDD, WCFhttp://blog.benday.combenday@benday.com