You are on page 1of 53

r

Obje ···c· ··,t D·:··· 0··· ·c· .ume mt M··" a ppinq mit M··" 0··· . n go··· D·:··· 81 ..

,"., .. ',"' ,', ... " ,.', '1 '1 .. ',' '1 ",':: . ,"I' ,'., ,'., '1 ". '1 "I ",' :: . ,'.. '1 .". r- . . ....

", ' - '::"". . ," - ..... :.: .! I ""',' •••.• :.: '. , •••• :: ::",

[ .'. . . ." '.' '. . ..' .....•...... . . • .... . . .' '. , .' ". . ~ '. '. '. '. ~ '.' .' '. . . .' '. . ~ 1 ..... . . .' . . •

. ' ',' ",,: .. ",,:

Uvve Schafer, 03/2011

/me

... ' ';' ",'

..

, ::/.,

'. Uwe Schafer (us@thomas-daily.de) '. CTO THOMAS-DAILY GmbH

'. Branche: Immobilieninformation '. Morphia Committer

Motiv .... ···::'···:::··:··::a············I tio n···········

"',' ..... ,.' .1.. ' .... :, ...•.. '. I ", " ..... , r

Motivation

All h I- hk -t JPA' JDBe"

. ", [ ", ", . ,'.", .", "'. I "'. [ ",", [. ':' ::..... 'I".' . ",", ',I: ,:' :

'n Ie '·elen zu"vs.>, < •••

MongoDB Java Treiber vergleichbar mit JDBC: '. schnell, rnacbtiq

jedoch gleichzeitig

'. unbequem, low-level

Morphia bietet

'. Abstraktion von Konzepten des Treibers (DBCursor etc.) '. POJO-Persistenz

'. dadurch typsi cher

'. API fOr Konstruktion von Queries, Updates, Deletes

Motivation

Abq ren [z·· .. ··· u n g': [z····.'· U J P:,A· .... ::',::·'·· vs J 0':" B['C··'·······:

[ ,., ,'1 <>' ',,: .'.' .••... , ... " ". ..' ,",:,',' ,,'[.' < .. ,>

[. mongoDB-only

'. (natOrlich) keine Transaktionen

[. kein Open-Session-In-View Muster

[. keine Dirty-Checks, kein implizites Speichem [. keine verschiedenen Cache-Scopes

'. kein XML, minimale Konfiguration in Java

Morphia versucht mit rnoqlichst wenig II Magi ell auszukommen

Motivation

Features

'. POJO Mapping

'. Lifecycle callbacks

'. Datastore

'. Query-Builder API

Erwei terungen

'. GWT Support

'. JRebel intergration

'. Gui ce Plugi n

'. Logging SLF4J

'. JSR330 Validation

I - - I- -

rima isrerunq

I nitialisierun 9

Mongo mongo = ... ;

Morphia morphia = new Morphia();

morphia.map(Entityl.class); morphia.map(Entity2.class);

mo r phia. mapPac kag e ( II com. example" ) ;

morphia. mapPackageFromClass(Entityl. class);

Datastore ds = morphia.createDatastore(mongo, IMyDB");

ds.ensurelndexes(); ds. ensurecaps( );

'. Applikationsweite Singletons mbglich (Morphia, Datastore) '. Entitatenklassen werden bei .map geprOft

'. ensurelndexesO und ensureCapsO beziehen sich auf gemappte Klassen

Initialis ierung



Ma········ p ····p· .. ···ln········· g · 1

.......... ' '.. . ..

. ". . r

Mapping

Oberblick

@Entity class Note { @Id @Version

Objectld id; long version;

@Property(lItxtll)

St ring text;

@Indexed @Indexed(GE02D)

St ring ti tIe; doub Le [] latIng;

@Reference @Reference(lazy - true)

Person author;

List seenBy = new LinkedList();

@Embedded @Serialized

List comments = new LinkedList(); Certificate cert;

@Transient

boolean isPersistent - false;

@PostPersist @PostLoad

void markPersistent() { this.isPersistent - true;

}

}

> db,MinimalEntity,find();

{ II _id II 0 bj eet Id ( 114d 567e33a693297 4b7 f3age311 ) I

lIelassNamell : lIexample,MinimalEntityll

Mapping

@Entity class MinimalEntity { @Id Objeetld myld;

}

ds,save(new MinimalEntity());

erzeugt

}

'. Anforderungen an Entitatenklassen: @Entity, @Id und (momentan noch) "non-arq

constructor'

'. Name der Collection = class.getSimpleNameO '. id heisst immer id

'. Typ egal, wird automatisch vergeben falls vom Typ Objectld '. Klassenname als 'discriminator

Mapping

Einfache Eigenschaften

> db.MyCollectionName.find();

{ II _id II Ob j ec t Id (1I4d567d d7e b2c297 46 bbc7a9311 ) ,

II someS t ring II : II example St ring II ,

II ill : 11511 }

'. @Entity.value definiert Name der Collection

'. @Entity.noClassnameStored m6glich, falls Inhalt der Collection uniform '. @Entity.concem & @Entity.slaveOk definieren Voreinstellungen furs

S pei chern! Abfragen

'. @Property.value definiert Namen im Dokument

@Entity( value

noClassnameStored concern queryNonPrimary

class FlatEntity { @Id Objectld myld; St ring someSt ring - @Property (II ill) int somelnt

}

- IIMycollectionNamell,

- true,

- WriteConcern.SAFE,

- true )

lIexample Stringll;

- 5;

Mapping

@Entity class CollectionContainer {

int[] intArray;

List<Integer> LinkedList<Integer>

intListl; intList2;

@Embedded(concreteClass=LinkedList,class)

List<Integer> intList3;

Map<Integer, String> intMap;

collectionContainer() {

this,intArray - new int[] { 1, 2 };

this,intListl - Arrays,asList(3,4);

this,intList2 - new LinkedList(Arrays,asList(5,6)); this,intList3 - new LinkedList(Arrays,asList(7,8));

this,intMap - new HashMap<Integer, String>(); th is .J n t+tap . put (1, "e i ns" );

th is , in tMa p , put (2, II zwei II );

}

}

ds,save(new CollectionContainer());

> db,CollectionContainer,find();

{ II _id II 0 bj ect Id ( 114d 5684ba69d7297 427 4cl120 II ),

II c La ssname" II example, CollectionCont ai ne r II r

"Lnt Ar r ay" [1, 2 l.

lIintListlll [3, 4 l .

"Lnt Li s t z" [5, 6 l .

lIintList311 [7, 8 l .

II int Ma pll {1I211 : II zwei II ,11111 II ein s''}

Mapping

}

'. Listen werden wie Arrays behandelt

'. Implementierungen k6nnen durch Deklaration oder Annotation festgelegt werden '. Vorei nstellungen: ArrayLi st fUr Li st, HashSet fUr Set und HashMap fur Map

Mapping

E I· n ". b e····· tte n e······,·I· g'" e'" sn e······,· r' Ty'" p ,". e"" ""n'"

I . ",' ',' I ",' ",' I '. " · .. t •••• :.:··· " I

• •• • •• • •• • ••• • •• • • • o.

[ .' '. '.......... " "' .. ' ..•. "', .' ..•. :. .: ~.~ .: "'. . . . • . "', .' ..•. .~: .' . '. -t . " •.

@Entity class Person { @Id ObjectId id; String firstName;

St ring lastName;

Phone phone;

@Embedded(lIphone211) Phone secondaryPhone;

public Person(String firstName, String lastName, Phone phone, Phone sec) { ... }

}

class Phone { PhoneType type; St ring numbe r;

Phone(PhoneType type, String number) { ... }

}

enum PhoneType {

HOME, WORK, MOBILE

}

> db,Person,find();

{ II _id II : 0 bj ect Id ( 114d 5687f1ab f8297 443982e30 II ),

II c La ssname" II example, Pe r so nil ,

II fir s rName" II Bobll,

II las tName II II t.e e"

,

{ II type" { II type"

Mapping

E I· n ". b e····· tte n e······,·I· g'" e'" sn e······,· r' Ty'" p ,". e"" ""n'"

I . ",' ',' I ",' ",' I '. " · .. t •••• :.:··· " I

• •• • •• • •• • ••• • •• • • • o.

[ .' '. '.......... " "' .. ' ..•. "', .' ..•. :. .: ~.~ .: "'. . . . • . "', .' ..•. .~: .' . '. -t . " •.

Person p = new person(IIBobll, II Leell,

new Phone (PhoneTy pe, WORK, 11123411), new Phone (PhoneTy pe , MOB ILE, 11567811));

ds , save( p);

II pho ne II

II pho ne211

IIWORKII, IInumberll

II MOBILEII "number "

,

11123411 } 11567811 }

}

I. aile Typen, die ni cht als @Property behandelt werden k6nnen, werden automatisch

ei ngebettet

I. beliebige Klassen k6nnen eingebettetwerden

I. auch diese mOssen (momentan noch) einen 'non-arq' Konstruktor besitzen '. Enums werden via Name gespeichert

I. @Embedded.value definiert Namen im Dokument

R e··' "'Ia' 'tl- 0'" . Il e'" ""n" zu a' Il d e'" ". I e'" ""n" D·· .. ·· 0'" . ku 'm'" ". e'" mte ""n'"

. '.,' . ,"1 . . .'.. . I .. ',' . I ..... . r- 'I' . I .. I .,'.,. ,' ... ,. . I .. '.. _' ,/ . I "I .,'.,. . I . ,",' . I

. ," "1 I '. . ." ..... ,... ,'j I • ,r . ," .. '. .:: . . -...... .. " . ,"

" .. ' . .' ". . ~ '. '. ". . . ..' . .' .". .' ". . . '. '. . .' " .. ' . .' .' . .' . ..' '. . ". .' " .. ' . .' . . .'

@Entity class Employee { @Id Objectld id;

String firstName; St ring lastName;

II Exception falls Ziel nicht existiert (Voreinstellung) @Reference(ignoreMissing = false)

Department department;

@Reference(lazy = true) II ersetzt durch Proxy List<Hobby> hobbies = new ArrayList<Hobby>(); I I ...

}

'. ignoreMissing=faJse wirit Exception beim Laden falls Ziel Coder ein Teil davon)

fehlt

'. lazy=true ersetzt Ziel oder Liste von Zielen durch Proxy

'. mapped-by oder 'inverse Navigationl wird von Morphia nicht unterstOtzt '. P ro>o/-Instanzen si nd seri ali si erbar

Mapping

.l-~

t.,....,:~,

> db.Department.find()

{ II id II Db j ec t Id (1I4d5 798aee235297 49aca bec s" ) ,

II c La ssname" II example. De pa r tment II ,

II name II II I Til

Mapping

R e··' "'Ia' 'tl- 0'" . Il e'" ""n" zu a' Il d e'" ". I e'" ""n" D·· .. ·· 0'" . ku 'm'" ". e'" mte ""n'"

. '.,' . ,"1 . . .'.. . I .. ',' . I ..... . r- 'I' . I .. I .,'.,. ,' ... ,. . I .. '.. _' ,/ . I "I .,'.,. . I . ,",' . I

. ," "1 I '. . ." ..... ,... ,'j I • ,r . ," .. '. .:: . . -...... .. " . ,"

" .. ' . .' ". . ~ '. '. ". . . ..' . .' .". .' ". . . '. '. . .' " .. ' . .' .' . .' . ..' '. . ". .' " .. ' . .' . . .'

De par t me n tit = n ew De pa r t me n t ( II I Til ) ;

Employee bob = new Employee(IIBobll, II Leell, it); ds. save(it, bob);

.l-~

t.,....,:~,

}

> db.Employee.find();

{ II _id II Db j ec t Id (1I4d5 798aee235297 49 bca bec s" ) ,

II cLa ssuame" II example. Employeell ,

IIfirstNamell IIBobll,

IIlastNamell II Leell

,

II depa r tme nt II {

lI$refll

lI$idll

"Depa r tmen t ",

Dbjectld(1I4d5798aee23529749acabec611) }

}

'. n:O .. l wird zu DBRef

'. n:O .. n wird zu Array von DBRefs

Callbacks

> db,EntitywithCallbacks,find();

{ II id II Obj ect Id ( 114d579fd 5b853297 42b58b b2311 ) ,

II c La ssname" II example, En ti t yWi t hCallbacks II,

IIlastModifiedll NumberLong(1I129758818100911),

II foo II II ba r II }

Callbacks

C lib k A· t t·

a· · •• ··.a.·;:,c·.: .........H[n·'·· Il 0 •• ·· •.•.• · a.···, ... ·,··,[ 10 •• ·· •.•.• ·[n·'··e •• ·· •• ' Il

[ •• ' .. ' .. ' .". I • ", '0 ,', '. •• ".'

@Entity class EntitywithCallbacks { @Id Objectld id;

long lastModified = 0;

@PreLoad void beforeLoadFromDB() { }

@PostLoad void afterLoadFromDB() { }

@PrePersist void beforeMapping() {

this,lastModified = System,currentTimeMillis(); }

@PreSave void beforeStoring(DBObject afterMapping) {

afte rMapping, put (II roo", II bar " );

}

@PostPersist void afterStoring() { }

}

[. ggf. Nachteil: reu der Entitat (enge Kopplung)

Callbacks

EntityListen ers

class Listener 1 {
@PreLoad void beforeLoad FromDB (Object e) { } ,t-,
, .-...;.'
@PostLoad void onLoadFromDB (Object e) { }
}
class Listener2 {
@PrePersist void beforeMapping (Object e) { }
@PreSave void beforeStoring (Object e, DBObj ect a fte rMapping) { }
@PostPersist void afterStoring (Object e) { }
} @EntityListeners({ Listenerl.class, Listener2.class }) @Entity class Person {

@Id Objectld id;

/ / ...

}

'. Annotation der Entiat (Kopplung)

'. machen Querschnittsaufgaben wiederverwendbar '. Callbacks wird hier die Entitat Ubergeben

'. Nachteil: oft "unschorer' Code (instenceot, Reflection usw)

Callbacks

Entityl nterceptor

pub lic interface Entitylnterceptor { ,t-,
void prePersist (Object e, DBObject d bObj , Mapper mapr) ;
, .-...;.'
void preSave (Object e, DBObject d bObj , Mapper mapr) ;
void postPersist (Object e, DBObject d bObj , Mapper mapr) ;
void preload (Object e, DBObject d bObj , Mapper mapr) ;
void post load (Object e, DBObject d bObj , Mapper mapr) ;
} II fOr aIle Entitaten gOltig

morphia,getMapper(),addlnterceptor(new AbstractEntitylnterceptor(){ void preSave(Object ent, DBObject dbObj, Mapper mapr){

I I '"

} } );

'. vollige Entkopplung von der Entitat

ln d······ izes .

:" • '. . ': ',' ,",I., .

\ 1·/ 1·· .. ·· ,

indexes, Caps

@I'n·[··d···,·e·····,····x··e····,'··d .. ·,

,I . ,"' .... ,", •. " .. 1

', ': .. ', ,'" .

@Entity class IndexTestEntity { @Id Objectld id;

@Indexed

long long 1 - 0;

@Indexed( II voreinstellungen background = false, unique = false, dropDups = false, sparse = false, value = IndexDirection,ASC)

long long2;

Embedded embedded;

}

class Embedded { @Indexed

String willBelndexed

- 1111,

- ,

}

class EmbeddedChild extends Embedded {

II wird nicht indiziert, da z,Z, nicht statisch ermittelbar,

II dass/ob EmbeddedChild anstelle von Embedded in IndexTestEntity verwendet wir @Indexed

long willNotBelndexed;

}

> db,compoundlndexEntity,getlndexKeys();

[ { II _id II 1} ,

{lIflll 1, IIf211 : 1 },

{ II f311 1 }

indexes, Caps

Zusamm .. ··e··· ""n"9 e'" "'s'e'" itzte ". lndize "'5'

•..... ,"I' '1 "1 '1·1·"·,··1 .",.,'., .• I·.· ',' ....•. . ,",' 'I "1 ,",'. I:,',

. . -'t···· I I I .. "' ." ."' ',-'t··· .. "' .....•.. . ." . ,I .....•. . ," ',' ",

". • • '. '... ~ '. " .. ' . .' '. . ~ 1 " •. ' . ." '. .... . .' '. . •..... . . .' '. ". . " .. ' . ." ". . . . .

@Indexes({

@Index(name = IImycompoundlndexll,value = IIfl,f211)

})

@Entity class CompoundlndexEntity { @Id Objectld id;

long fl; St ring f2;

@Indexed St ring f3;

}

]

'. sind auf Ebene der Entitat definiert

'. k6nnen zusammen mit einfachen @Indexed verwendetwerden

> db,Coffeeshop,getlndexKeyS();

[ { II _id II : 1 } I { II la t Lng II : II 2d II } ]

indexes, Caps

I d D'·· · G······ EO······2·····D·· 'n: eX.rrectl o[n . i ......~i/ ...•.....

@Entity class coffeeShop { @Id Objectld id;

@Indexed(IndexDirection,GE02D) daub Ie [] lat Lng = nu 11;

/ /, , ,

}

[. Geo Indizes werden ahnlich definiert

> db.LogEntry.find()

{ II _id II 0 bj eet Id ( 114d 57e2902bOe297 44188b81d II ),

II cLa ssuame" II example. Log En try II ,

II ill 2

indexes, Caps

C d C·· II ·

·····1·· [ ",'. "', [ ",". "', :,., ',"'. ····l :., : :...... . : , : ,.. : [ "'I'" .·1·.·.·

appec ··..0 ections

@Entity(eap = @CappedAt(eount - 2, value - 1 * 1024 * 1024)) class LogEntry {

@Id Objeetld id;

St ring msg;

LogEntry(String msg) { this.msg = msg;

}

}

ds.save(new LogEntry(1I111), new LogEntry(1I211), new LogEntry(1I311));

}

{ II _id II

lIelassNamell II ill

o bj eet Id ( 114d 57e2902bOe297 44288b81d II ), II example. Log En try II ,

3

}

'. ds.ensureCapsO anaJog zu ds.ensurelndexesO

Datastore API

Datastore API

D a ta s to re I'n· te . rtac e· .

. ,"I' . ,"I' I", :' .. ' ,,;'.' ", '1';' r- '",' . ,"I' :"',':' . ",

. . , , ,

. . .' .

. I . j I."· '. . ," . ," . I ,. I • ,"

". . ~ '. '. ".'.'. . '. '. "....... .... . . .' '. .... . . .' ". . ~ '. . '. . .' ". . . .'

interface Datastore {

II Create

<T>

Key<T>

save( T enti ty);

II Read

<T,V> T get(Class<T> clazz, V id);

<T> T getByKey(Class<T> clazz, Key<T> key);

<T> Query<T> createQuery(Class<T> kind);

I I update

< T> Ke y < T> me r 9 e (T en tit Y ) ; I I ke i n II u p se r t II

<T> T findAndModify(Query<T> q, UpdateOperations<T> ops);

<T> UpdateOperations<T> createUpdateOperations(Class<T> kind);

<T> UpdateResults<T> update(T ent, UpdateOperations<T> ops);

II Delete <T> void <T,V> void

<T> T

delete(T entity); delete(Class<T> clazz, V id); findAndDelete(Query<T> q);

I I ...

}

Datastore API

Das u n rv ::·e···· ·····r· m 1"'·'· I" ·e···· ··'··I·d"· II· c hi" ·e·······,·· 81 10'···· . g': 81 'e"· ··'··I·S':·: piel

. . ." 'l '.'. .'. ' .' ,

·'1 ~ -'I'" . . ... , .. : . ," .. " .l . I . ," .:., •• ' - .:., ." ',-'I·· '. . ."

". . ~ '. . ". ',... • ". . . .' ". . . .' '.' .' . . . .' " •. ' . .' . • ". . . .' '. . ~ 1 .... . . .' .' . . '. " .. ' . .'

. . . .

abstract class BasicEntity { @Id Objectld id; } @Entity class Article extends BasicEntity {

St ring headline;

St ring text;

@Reference Author author;

List<Comment> comments = new LinkedList<Comment>();

Article(Author author, String headline, String text) { ... }

}

@Entity class Author extends BasicEntity { String displayName;

Author (St ring displayName) { ... }

}

class Comment { String displayName; String commentText;

Commen t (S t ring di splayName, St ring text) { ... }

}

Datastore API

Sip .. e·· ··1- c h e·· nn

r- ...... ,", "", ·1 .. ··,"'" '1

' •. ," • I . ,"

...... ',' ',.,' .... ','

Au t ho r bob = n ew Au tho r ( II 80 b II ) ;

Article article = new Article(bob, IIMorphia is funll, II He re is t he Article t ext II );

article. comments. add(new Comment(IIDougll, IIFIRST!II)); art icl e . co m me n t s . ad d ( n ew Comme n t ( II Pe t e r II, II me too. II ) ) ;

ds. save(bob);

ds.save(article, WriteConcern.SAFE);

'. WriteConcem kann bei jeder schreibenden Operation angegeben werden I. sonst gilt Voreinstellung fUr Datastore bzw. Entitatenklasse

Datastore API

S p .. e·· ··1- c h e·· nn

r- ...... ,", "", ·1 .. ··,"'" '1

' •. ," • I . ,"

...... ',' ',.,' .... ','

> db.Author. find();

{ II _id II 0 bj ect Id ( 114d 5842729717297 483e9d c7811 ),

II c La ssname" II example. blog . Aut ho r II r

II name II II 80 b II

}

> db.Article.find();

{ II id II 0 bj ect Id ( 114d 5842729717297 484e9d c7811 ),

II c La ssname" II example. blog . Ar t Lc.Le" r

II headline II II Mo r phia is fu nil r

IItextll IIHere is the Article textll,

II aut ho r II { II $ ref II : II Au t ho r II r

II $id II : ObjectId(1I4d5842729717297483e9dc7811)},

II comme nt s II [

{ IIdisplayNamell

II comme nt Tex t II

},

{ IIdisplayNamell

II comme nt Tex t II

II Do ug II r

II FIRST! II

II Pe te r II r

II me too. II

}]

}

Datastore API

AI I Il d e··· ... r'n··

"I "1' . ',' ," "I

I

" . '.~ < ... .:

II erneutes speichern

article, comments, add(new comment(IIMarkll, IIdon't think SO,II));

ds,save(article);

II kein Upsert, nur gesetzte Felder werden Oberschrieben ds,merge(article);

II Massenanderungen

UpdateOperations<Article> what - ds,createUpdateOperations(Article,class); what,set(lIheadlinell, IICENSOREDII);

Query<Article> where - ds,createQuery(Article,class) ,field(lIheadlinell)

, co nt ain sIg no r eCase (II mo r p hia II ) ;

UpdateResults<Article> result - ds,update(where,what); System,out,println(lIupdated II + result,getUpdatedCount() + II documentsll);

II atomare operation, andert nur den ersten Treffer Article newVersion - ds,findAndModify(where,what); I lode r

Article oldVersion - ds,findAndModify(where,what,true);

Datastore API

L II h

O· S··········C····,·· ., ... e······,···'n·,···

. t • I •. "

. ". " .. ,' ,'

II Anhand einer Referenz ds,delete(article);

II Anhand der Id ds,delete(Article,class, article,id);

II oder anhand eines Query

WriteResult result = ds,delete( ds,createQuery(Article,class),field(lauthor"),equal(bob) ) ;

system,out,println("deleted II + result,getN() + II articles");

II atomare Operation, loscht nur den ersten Treffer

Article nextToProcess = ds,findAndDelete(ds,createQuery(Article,class));

Q A

. ' .

....... < - ",,"

..... , .... -- ..... , "". _.'

uery .iPI

Query API

E I- n ta c "'," hi" e·······,,·· Q .•.....•......•.... r u e····· """r'l- e····· ·,'··5····,····

I I. I .. "' .. ,". . .. " .. " . t

"'. . ~ '. . '.' " .. ' . " ....."...,... . . " ". . . ," ".

List<Article> bobsArticles = ds,createQuery(Article,class) , field ("author" ) , equal( bob)

,offset(30),limit(10)

,asList();

II verwendet Server Cursor, nicht notwendigerweise aIle Objekte im RAM Iterator<Article> i = ds,createQuery(Article,class)

, field ("author" ) , equal( bob) ,batchSize(10),queryNonPrimary(),disableTimeout(),

,iterator();

long articlesWithPeterCommenting = ds,createQuery(Article,class) ,field(lcomments,displayNamel),startsWithIgnoreCase("pet")

, co u n tAll ( ) ;

[. limiUoffsetfUr Paginierung [. P unkt- Notati on mag Ii ch

'. automatische Obersetzung von Java-Feldnamen nach Dokument-Feldnamen

'. automatische PrUfung von Typenkompatibilitat (Wamung, wenn z.B. bob nicht vom deklarierten Typ)

S · II Q. . ·

pezie ere ouenes

long somethingunsupported = ds.createQuery(Article.class) .disablevalidation()

· f il t e r (II ... II I • • • )

· co u n tAll ( ) ;

long beyondQueryLanguage = ds.createQuery(Article.class) · field (liauthoril ) • equal( bob) .where(lIthis.headline.length>301l)

· co u n tAll ( ) ;

Iterator<QueueMessage> tailable = ds.createQuery(QueueMessage.class) .queryprimaryonly()

· field (II name II ) . eq ual (name) .field(lIstatell).equal(QueueMessage.State.NEW) · tail ( );

'. automatische Obersetzung & PrOfung abschaltbar

'. von Morphi a nicht unterstUtzte Features erreichbar Uber quel)l.fflter(String condition, Object value);

'. Mere fUr Javascript

' •. tail 0 liefert Iterator der bei .hasNextO blockt, falls keine weiteren Treffer vorhanden

Query API

II aIle in Rechteck (Z,B, Map)

II South-West & North-East definieren Rechteck Query<coffeeShop> alllnMap = ds,createQuery(CoffeeShop,class)

Ifield(llatLng"),within(sw_lat,sw_long,ne_lat,ne_long);

. '-fb ... f~J

Query API

G Q.. ·

e···········O •• ·· •••.•••••..•.••.••...•.. U· e •• ". "lr"1 e •• ·· •• :s'

. . ' .. ' ".' "...

@Entity class coffeeShop { @Id Objectld id;

@Indexed(IndexDirection,GE02D) double[] latLng = {32,-171};

I I I I I

}

II die 10 nachsten coffeeShop zu lat/lng

Query<CoffeeShop> nearest = ds,createQuery(CoffeeShop,class) I field (llatLng" ) I nea r (lat, Ing) I limi t (10);

Query API

Que" "ry': A: " P"I

",'.,", ..... , ..... :.: ::;' ", .. '.'

",.~ < ..... : .'~: . .. ,:.: " .

interface FieldEnd<?> { FieldEnd<?> not();

T exists();

T doesNotExist();

II Vergleich
T greaterThan (Object val) ;
T greaterThanOrEq (Object val) ;
T lessThan (Object val) ;
T lessThanorEq (Object val) ;
T equal (Object val) ;
T notEqual (Object val) ;
II Regulare AusdrOcke
T startsWith (5t ring prefix);
T startsWithlgnorecase (5t ring prefix);
T endsWith (5t ring suffix);
T endsWithlgnorecase (5t ring suffix);
T contains (st ring string);
T containslgnorecase (5t ring suffix);
II •••
} Query API

Que" "ry': A: " P"I

",'.,", ..... , ..... :.: ::;' ", .. '.'

",.~ < ..... : .'~: . .. ,:.: " .

interface FieldEnd<?> {

I I ... Ar rays und Listen

T hasThisOne (Object val);

T hasAIIOf (Iterable<?> vals);

T hasAnyof (Iterable<?> vals);

T hasNoneOf (Iterable<?> vals);

T in (Iterable<?> vals);

T notln (Iterable<?> vals);

T hasThisElement (Object val);

T sizeEq (int val);

II raumlich
T near (double x, double y) ;
T near (double x, double y, boolean spher ical);
T near (double x, double y, double radius);
T near (double x, double y, double r ad Ius , boolean sphe rical);
T within (double x, double y, double radius);
T within (double x, double y, double r ad Ius , boolean spherical);
T within (double x i , double y i , double xz. double y2);
} '. Unit-Tests demons1Jieren die VVirkungsweise der o.g. krtterien am besten

II Query

{ II $or II : [ { IIwidt hll : 10} f { II wid th" 5 f II height II 8}]}

Query API

Kriterienqruppen: AND und OR

Query q = ds,createQuery(Rectangle,class); q , or (

q .cr i teria( II wid th") , equal( 10) f q,and(

q , c rite ria (liwid t hll ) , eq ual (5) f q,criteria(lIheightll),equal(8)

) ) ;

'. Schachteln ist moglich

'. Einschrankungen des Servers beachten

Praxistipps

P raxistipps

FI- eld .. · N····· a·",··[m·,····,·· ·e···· ..... K·// ·O .. ······[n·,·· 5':'" tante .. ·· ·····[n·,··

, l· '. . . . ,

. ." .' r ."'.~.. j I I . ." . ", ..... .'. . '.' . j > I . ."

" ' ".... . ". ~" "... . .' ". ", "', .. / . ". '. ", .. ~ " ,,"... . .'

@Entity class Author extends BasicEntity {

public final stat ic St ring _displayName = FieldName. of( II displayName"); ·t:J

String displayName; / / ...

}

ds.createQuery(Author.class)

. field (AU t ho r . _di splayName) . sta r tWi t h 19 no r eCa se ( II p" );

[. Offensichtlich, aber umso wichtiger

'. UnterstUtzung durch IDE (Autovervollstandigung) [. fail-fast (Exception beim Laden der Klasse)

[. IDE gibt Aufschluss Uber haufige Verwendung in Queries

[. hi Ifreich in anderen Kontexten (Web-Frameworks, RichClients, ... )

P raxistipps

O · · · h S

[ ", ".1 [ ", ","", ", ," .. ," .' .", .", "' ," 1:····· [ ", ", "'. [ . [ "'. [ ", ",

ptimisnsc · esperren

@Entity class Article extends BasicEntity {

@Version

long version;

St ring headline; St ring text;

/ / ...

}

'. @Version vorn Typ long oder Long

'. wird geprOft und gesetzt beirn Speichern

'. ConcurrentModificationException falls Version unerwartet

P raxistipps

Sc""" hi" Il ·e···· ·,···lle··· .. ,···@i·········R'· ete ., ... Ir· ·e······,···[n·,·· 'c""" ·e···· ., ....

• I .• " •. " ••. ," ,".. ',", " •. " .• " • r •• ".

", .. ,' ',' ,' : " ,' ,' ,' ', .. ,' ','

@Entity class Article extends BasicEntity {

St ring headline; St ring text;

@Reference(lazy=true, ignoreMissing=true) Author author;

List<Comment> comments = new LinkedList<Comment>(); / / ...

}

[. Voreinstellung fOr ignoreMissing ist false

[. dann PrOfung auf Existenz des Ziels notvvendig (DB-Lookup) '. dadurch ggf. langsam

Sip' .... e'" . "'1· c"··· h e'" . ". I I e'" . "'1· h e····· ""n' " fo···· "1 g'" e····· ". fu·· r' Il e····· ". u e····· ". E Il " titate ""n' "

. ",' " I",' '. " I",' I . . . '. " I '. " ',' I . I ",' I

'. . ." • I . ." . ." . ." •.••.. .... . ." . '.' . . I ~ I '.' .

. . "... . .' '.' .' "... . .' "'.. . .' "' .. ' .• ' "'. . . / ",' ~ 1 "' ....• ' ". " " ....• ' .•.• "' .•..• ' '. ,,', .. ~" " "" ...•.

. . . .

Aut hor pete r = new Aut hor (lipeteril );

Article a1 = new Article(peter, IIHeadline111, IIfooll); Article a2 = new Article(peter, IIHeadline211, IIbarll); d s , save(a1, peter, a2); II Fehler

=> MappingException: Error mapping field:example,blog,Article,author

'. Initi aJisierung von i d hi 1ft

@Id Objectld id = new Objectld();

I. falls PrOfung auf Persistenz notwendig, statt ~d=null) besser:

@Transient

private boolean persistent = false;

@PostLoad @PostPersist

private void markPersistent(){ persistent = true;

}

public boolean isPersistent(){ return persistent;

}

P raxistipps

"

'i~

P raxistipps

E'rweiterung: JSR303 Validierunq

morphia,getMapper(),addlnterceptor(new Morphiavalidation());

@Entity class Author extends BasicEntity { String displayName; @org,hibernate,validator,constraints,Email II oder @org,apache,bval,constraints,Email St ring email;

I I '"

}

'. JSR303 Validation mittels Hibemate-Validator oder Apache BVAL

'. ConstraintViolationException beim Speichem falls Priifung fehlschlagt

'. @Valid notvvendig um eine Oberpriifung von eingebetteten Klassen auszul6sen (so definiert von derVali dati on APO

P raxistipps

E'rweiterung: EntityScanne'r

public class ApplicationMappings {

public ApplicationMappings(Morphia morphia){ m.mapPackageFromClass(SomeEntity.class); m.mapPackageFromClass(OtherEntity.class);

}

}

II oder Erweiterung

new Entityscanner(morphia);

II bzw. fOr genauere Kontrolle

new Enti tyScanner (morphia, new Predicate<St r ing>() { ... });

'. Klassenprufung und ensurelndexeslCaps setzen volistandiqes Mapping aller Entitatenklassen voraus

'. E ntityS canner "rnappt" aile @Entity-markierten Klassen im Classpath '. Mapping komfortabler und robuster

P raxistipps

Integration DI Framework

public interface ObjectFactory {

Object createlnstance (Class clazz);

Object createlnstance (Class clazz, DBObject dbObj);

Object createlnstance (Mapper mapr, MappedField mf, DBObject dbObj);

Map createMap (MappedField mf);

List createList (MappedField mf);

Set createSet (MappedField mf);

}

public interface InstanceFactory { <T> T newlnstance (Class<T> c); <T> T onlnstantiation (T instance);

}

'. ObjectFactory zustandiq fUr Auswahl der zu instanziierenden Klasse '. Instance Factory ausschlieBlich zustandig fUr instanziierung

'. Instance Factory einfacher Weg, um DI Framework einzubinden '. work in progress

P raxistipps

Den ·0····· ·r·'m·I······I··a··"'··II·S,.· .. ier un g': beim S··(·····,p·······e··········I··C·"'·· hem

, . . , '.'"

. ," '. . I I I ',',", . ," . • . ' •. ," .", ':1: .. ' ,"' . I . ,"'

" .....• ' "', .. f "0 • ~ '. .' • " •••••• ' ...,' ", • ~ 1 [ .' . "....... '. ..•• '. ".,..... . . . .' "., ...• ' . . . .

@Entity class Article extends BasicEntity{ String authorName;

II falls interessant zur Anzeige @PrePersist void adjustAuthorName(){

authorName = author.getDisplayName();

}

II falls nur interessant fOr Query

@PreSave void adjustCatgoryName(DBObject dbObj){ dbObj.put(lIcategoryNamell, getcategory().getDisplayName());

}

}

ds.createQuery(Article.class).order(lIauthorNamell);

ds.createQuery(Article.class).disableValidation()

. field (licategorYNamell). equalIgnoreCase( "monqodb"}:

'. NatUrlich mUssen diese Daten bei Updates/Deletes entsprechend aktualisiert werden

P raxistipps

Einfache MessageQueue

@Entity class QueueMessage{

@Id ObjectId id;

Object payload;

@Indexed State state = State,NEW; @Indexed String name;

static enum State { NEW, PROCESSING, DONE, FAILED };

}

Query<QueueMessage> q = ds,createQuery(QueueMessage,class) ,queryprimaryonly()

, field (" name II ) , eq ual (name) ,field(lstate"),equal(QueueMessage,State,NEW);

updateOperations<QueueMessage> markStarted = ds,createUpdateOperations(QueueMessage, class) ,set("state", QueueMessage,State,PROCESSING);

wh i Ie ( t ru e ) {

try{

QueueMessage m - ds,findAndModify(q, markStarted); if (m != nu l l )

{

/ /, , ,

Fragen?

Q&A

http://code.googl e. com/p/morp hi aJ Ausblick

'. Vereinfachung der Initialisierung und Konfiguration '. Verbesserung der intemen Struktur

'. Verbesserung der Fehlermeldungen

'. GridFS Support

Weitere Tutorials z.B.:

'. IBM DeveloperWorks http://tinyurl.com/dw-mornhi~

'. JavaMagazin 03/11, Morphia: POJO-Persistenz mit mongoDB

You might also like