Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

95
Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Transcript of Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Page 1: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Object-Relational Mapping in the Microsoft World

by Benjamin DayBenjamin Day Consulting, Inc.

Page 2: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

About the speaker

• Owner, Benjamin Day Consulting, Inc. Email: [email protected] Web: http://www.benday.com Blog: http://blog.benday.com

• Trainer Visual Studio Team System, Team Foundation Server

• Microsoft MVP for C#• Microsoft VSTS/TFS Customer Advisory Council• Leader of Beantown.NET INETA User Group

Page 3: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Agenda

• Overview of “the problem”• Brief discussion of the options• LINQ to SQL• NHibernate• Entity Framework

Page 4: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

THE PROBLEM

Page 5: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

The Problem

• Mismatch between objects and relational databases Objects = inheritance, polymorphism, composition Database = rows of data with relationships to other rows of data

Page 6: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

One Table Per Class

• The class looks like the table• Great candidate for a typed dataset

Simple Works nicely with DataAdapter because of RowState

Page 7: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Limitations of Typed Dataset Route• Tight coupling with the database• Inheritance is difficult• How 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 validation Validation goes in the “set” property

Page 8: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Object - DataRow Hybrid

• Every object wraps a typed DataRow• Properties control access to columns on the DataRow

Facilitates more complex validation

• DataRow becomes a data transfer object Still works nicely for System.Data integration

Page 9: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 values Phone number isn’t really just

a string http://www.jamesshore.com/Blog/

Page 10: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Coarse-Grained vs. Fine-Grained Object Model

• Fine-grained = More object-oriented• Data and properties are split into actual responsibilities

coarse-grained fine-grained

Page 11: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

But how do you save it?

• Four classes go to one table?• Five instances go to one table?

Page 12: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Inheritance, Collections, and Relationships

• Employee is a Person• Employee has Underlings• Employee has a Supervisor

Page 13: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Limitations of Object - DataRow Hybrid• Inheritance >1 DataRow at once

One 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 object

• How to save parent-child relationships? Employee has FK to a Supervisor Supervisor needs to be saved

first• Objects have ability to modify internal state of other objects

wrapping the same DataSet bugs & encapsulation• Number 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?

Page 14: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Object-Only Model

• No more DataRows• Classes are member variables, methods and properties• Clean “Domain Model” pattern

Business tier worries about itself Decoupled from the database

• Straightforward inheritance, polymorphism

Page 15: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 versa

• How 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?

Page 16: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Do you really want to solve these problems?

• Problems are solvable• Everybody writes their own solution• Persistence is a distraction from solving The Real Business

Problem

Page 17: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

AVAILABLE OPTIONS

Page 18: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Options

• LINQ to SQL• Entity Framework• NHibernate• Wilson OR Mapper• LLBLGen• And more…

Page 19: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL

• Available in Visual Studio 2008• “Better typed dataset”

Page 20: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL: Pros / Cons

Pros• You don’t have to write

data access code• Good for Rapid

Application Prototyping• Integrated into Visual

Studio• Designer support• Will generate the

database schema for you

Cons• SQL Server only• Limited inheritance

modeling (Table Per Hierarchy only)

• Closely tied to the database

• Unusual way of handling stored procedures

• Generates code

Page 21: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Entity Framework

• Microsoft’s first, real ORM solution (well…I guess this depends on who you talk to)

• In beta• Rumored to be released with Visual Studio 2008 sp1

Page 22: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Entity Framework: Pros / Cons

Pros• Full-featured• Not open source• Integrated into Visual

Studio• Designer support

(eventually)• Support for non-SQL

Server databases (eventually)

• Supports LINQ• Support Table-per-Type

Cons• Still in beta• Not open source• Version 1

Page 23: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

NHibernate

• Full-featured ORM solution• Open source• Based on Java’s Hibernate framework• Uses XML to map tables/columns to objects/properties

Page 24: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

NHibernate: Pros / Cons

Pros• Rich selection of

mappings• Inheritance modelling• Polymorphic queries• Established solution with

lots of current users• Support for multiple

database vendors• Open source• Free

Cons• Open source• Free• Not from Microsoft• 3rd party library• Limited to zero GUI

support• Currently doesn’t support

LINQ …but does have HQL

Page 25: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ TO SQL

Page 26: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Using the LINQ to SQL O/R Designer

• Define classes• Set up inheritance

Page 27: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL vs. Typed DataSets

• My $0.02 – LINQ to SQL is the new Typed DataSet

Page 28: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL vs. LINQ to DataSets

• DataSets in VS2008 are query-able with LINQ• DataTable’s object model has changed • DataTable now extends from TypeTableBase<T>• TypedTableBase<T> extends DataTable

• Backwards compatible

• No special way to fill the DataSet/DataTable with LINQ to SQL• Still uses DataAdapter

Page 29: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL vs. Raw SQL Access

• Hopefully you don’t do this…• The data access strategy of masochists everywhere

Page 30: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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/properties• Uses xml mapping files or attributes

• Comprehensive inheritance modeling• Has LINQ-like object query syntax

• HQL – Hibernate Query Language

• Multi-vendor database support• Oracle, SQLServer (2000 & 2005), MySql, Sybase, etc

• Lets you focus on the business problem rather than persistence

Page 31: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Using LINQ to SQL with Unit Tests

• When testing database code, database must be in a known state

• Easiest way: Wipe the database between tests DataContext.DeleteDatabase() DataContext.CreateDatabase() Database schema always in sync with code

• Harder way: Unit test manages transaction Rollback at end of unit test

Page 32: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

LINQ to SQL in an n-tier Application

• Common BaseClass• Hooking into save events

Auto-updating: ModifiedDate, ModifiedBy

• Keeping your code organized with the “Service Layer” pattern

Page 33: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Common Business Base Class

• Each business class should probably have similar fields Id ModifiedDate, ModifiedBy CreateDate, CreatedBy

• Bummer: LINQ to SQL isn’t great at this (NHibernate does this effortlessly) Mapped columns must be defined on the concrete

Page 34: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Code Demo

• Introduce a common business base class

Page 35: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Code Demo

• Implement the partials and auto-populate the base class properties

Page 36: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Auto-update base class propertiesfrom DataContext

• Generated DataContext & other objects are partial classes• Generated 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()

Page 37: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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!

Page 38: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 Stafford

Page 39: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Why Service Layer?

• Formally defines supported business tier operations (aka methods)

• Methods provide ideal target for unit testing• Keeps code organized

Code review: anything complex not in the service layer refactor Keeps code out of the UI

• Isolates the Domain Model (business) objects Minimize usage of the Domain Model objects outside of the Business tier

Page 40: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Service Layer in LINQ?

• CRUD operations for each business object • Any specialized “get” operations

Centralized place for any custom from-where-select’s

• Factory methods

• Create a BusinessFacade<T>

Page 41: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

ENTITY FRAMEWORK

Page 42: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Entity Framework Overview

• Still in beta• Official release with VS2008 sp1• Trying to be more than just an ORM• 3 layers

Conceptual Model (classes) Storage / Logical Model (table definitions) Mapping layer

Page 43: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

NHIBERNATE

Page 44: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

What NHibernate isn’t

• “Hibernate” has nothing to do with Windows Hibernate• Not object serialization• Not a code generator

Page 45: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

NHibernate To The Rescue

• .NET port of the Java-based Hibernate Object-Relational Framework NHibernate 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 clean

• Open-source, free software under LGPL http://www.jboss.org/opensource/lgpl/faq

• Ported by Tom Barrett, Mike Doerfler, Peter Smulovics, and Sergey Koshcheyev

Page 46: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

What is it?

• Object Relational Mapping Framework• XML-based• Mapping files

*.hbm.xml Classes/Properties Tables/Columns 1+ mapping files

• hibernate.cfg.xml Database Dialect: SQL Server, Oracle, MySQL, etc. Which assemblies to manage Which mapping files to use

Page 47: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

What it will do for you.

• Make your life easier• Simplify your data access• Allow you to focus on your business tier

Page 48: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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>

Page 49: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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>

Page 50: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<class>

• Simplest mapping• Maps a class to a database table• Attributes

“name” = name of the persistent class Fully qualified class name, assembly name (no “.dll”)

“table” = name of the table

• Required element <id> = defines object identity

• Common elements <timestamp>, <version> for optimistic concurrency <property> for mapping class properties to database columns

Page 51: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<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 key• Attributes

“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 discouraged

Page 52: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<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 length

Page 53: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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>

Page 54: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

The NHibernate Session

• Main point of contact ISession interface

• SessionFactory.OpenSession() • Objects are associated the ISession

Lazy loading

• Save, delete, and retrieve operations

Page 55: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Saving

• SaveUpdate() Person person1 = new Person(); // createperson1.Name.FirstName = "firstname1"; // set propertiesperson1.Name.LastName = "lastname1";session.SaveOrUpdate(person1);session.Flush();session.Close();

Page 56: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Transactions

• Call BeginTransaction() on the session

public 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; }}

Page 57: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Retrieving

• Query / HQL syntax HQL = Hibernate Query Language SQL-like queries against the object model Use for more complex queries (JOINs)

• Criteria syntax Build the query programmatically

• NHibernate Allows Polymorphic Querying

Page 58: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

HQL Sample•Find Employees by Supervisor’s Name

Page 59: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

HQL Sample

public IList FindSupervisorEmployees(string firstName, string lastName)

{ string hqlQuery = @"

from Person p where p.Supervisor.FirstName = :firstName and p.Supervisor.LastName = :lastName";

IQuery query = Session.CreateQuery(hqlQuery); query.SetParameter("firstName", firstName); query.SetParameter("lastName", lastName);

return query.List();}

Page 60: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 objects

Page 61: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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);

criteria.Add(Expression.Eq(propertyName, propertyValue));

IList list = criteria.List();

return list; }

Page 62: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Deleting

• Session.Delete(object instance)

Page 63: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Making Person More Fine-grained

coarse-grained

fine-grained

fine-grained

Page 64: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mapping Fine-grained Person

Page 65: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<component><component name="Name"

class="NHibernateResearch.Business.Name, NHibernateResearch.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 class

• Object 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 database

Page 66: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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>

Page 67: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 id

Page 68: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mapping Inheritance• Employee is a Person

Page 69: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<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)

Page 70: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mapping Associations & Collections• Supervisor is an Employee• Employee has Underlings

Page 71: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Associations

• Associations define relationships between classes• NHibernate 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 role

Page 72: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

<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=@currentEmployeeId

Page 73: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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>

Page 74: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 data

Page 75: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 1child1.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;

Page 76: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

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 IComparer

Page 77: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Collections

• Lazy loading lazy = “true” Expose collections interface not concrete class

ArrayList IList Hashtable IDictionary

Lazy-load proxy loads on first access• “inverse” attribute for bi-directionality

“child” has a reference back to the parent Employee has Supervisor Supervisor has Employees

• “cascade” attribute

Page 78: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

The “cascade” attribute

• Controls when changes to child objects are saved• Options:

“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 collection

Page 79: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

NHibernate, Collections, and Generics• Current release is NHibernate 1.2.1• Now supports generics

Page 80: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Nullable Columns & ValueTypes

• Nullable columns should be avoided even if you don’t use NHibernate

• Sometimes you need them• Sometimes you’re stuck with them (legacy databases)• Under .NET 2.0 – Use the “?” syntax for the nullable

properties on your classes

Page 81: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Auditing Info

• Auditing info common to all tables / classes CreateDate,

CreatedBy LastModified,

LastModifiedBy

• Base class functionality

• How to know when to update the values?

Page 82: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

ILifecycle

• Allows class to perform actions at certain times during the NHibernate “lifecycle” of the instance

• OnSave(), OnUpdate(), OnDelete(), OnLoad()

• Slightly “pollutes” object model with NHibernate specific code

• Now is deprecated IInterceptor

Page 83: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Code Demo

• Refactor Person to extend BusinessBase• Implement auditing on Person

Page 84: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Intellisense for NHibernate

• Eliminate the tedium• Eliminate the potential errors• Learn what else is in there• Download the source• Schemas in “src\NHibernate”

nhibernate-configuration-2.0.xsd nhibernate-mapping-2.0.xsd nhibernate-generic.xsd

• Copy to Visual Studio’s “Schemas” directory “c:\program files\Microsoft Visual Studio 8\Xml\Schemas”

• Restart Visual Studio

Page 85: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Contains(), Evict(), Lock(), Refresh()• Methods on NHibernate Session• Contains(object) – Queries the session to

determine if it is managing the supplied object Is 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 database

Page 86: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

“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”

Page 87: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Simplify Data Access With Generics• Persistent objects operations are almost identical

ISession 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 Simplify Gain compile-time type safety

Page 88: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Code Walkthrough

• Com.Benday.NHibernate• BusinessFacade<>

Page 89: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mapping: <query>

• Allows you to write HQL complex queries and store it separately from the code

• Assigned a unique name• Accessed through ISession.GetNamedQuery()• Executed via IQuery.List()

Page 90: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mapping: <sql-query>

• Write SQL queries against the native database• Still brings back persistent objects• ISession.GetNamedQuery(), IQuery.List()• <return class=“classname” alias=“table alias” />• Table alias must be in “{ }”

Page 91: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Design Strategies

• Model to schema Create the object model first, then create mappings Have 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

expected• Schema to model

Database first, then classes, then mappings Legacy development More difficult, more about the needs of the database and less focus on the object

model

Page 92: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Create Database Using SchemaExport • NHibernate.Tool.hbm2ddl namespace• Reads 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’s

Page 93: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Code Demo

• Use BusinessFacade<> • Use schema export from unit tests• Create an fixture base class• Create a PersonFixture• Create a Person class• Play around with [TestInitialize] & [TestCleanup]

Page 94: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Mappings: Create a UNIQUE database constraint

• “unique-key” attribute on the <column> mapping• Set the same value on all properties that should

participate in the key

Page 95: Object-Relational Mapping in the Microsoft World by Benjamin Day Benjamin Day Consulting, Inc.

Benjamin Day• Consultant, Trainer• Architecture, Development, Project Coaching• Microsoft VSTS Customer Advisory Council• MVP for C#• Leader of Beantown .NET User Group• VSLive, O’Reilly Conferences• Team System, Team Foundation Server,

NHibernate, C#, ASP.NET, TDD, WCF• http://blog.benday.com• [email protected]