Professional Documents
Culture Documents
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