ravendb - Event Store using nosql performance considerations -
this may more of general nosql infrastructure question.
with event sourcing scheme i'm saving event documents ravendb.
in domain model there multiple types of events, basic illustration below:
public abstract class event { public guid aggregateid { get; set; } public event(guid aggregateid) { aggregateid = aggregateid; } } public class newpersonevent : event { public string name { get; set; } public newpersonevent(guid id, string name) : base(id) { name = name; } } public class neworderevent : event { public datetime orderdate { get; set; } public double ordercost { get; set;} public neworderevent(guid id, datetime date, double cost) : base(id) { orderdate = date; ordercost = cost; } }
an event persisted event document no matter type of aggregate event from.
is best approach utilize 1 document type in ravendb events. or there benefits of grouping document types per aggregate
instead of having 'event' documents, instead have 'personevent' documents , 'orderevent' documents.
what pros , cons of each of 2 approaches, there performance issues?
are overriding default tag name events as...
docstore.conventions.findtypetagname = type => typeof(event).isassignablefrom(type) ? documentconvention.defaulttypetagname(typeof(event)) : documentconvention.defaulttypetagname(type);
then whenever query on event
works , retrieves events. session.query<event>()
if so, can shoot in foot because if want subset of events , session.query<newpersonevent>()
it's going retrieve events since overrode tag convention in beginning. can still way wouldn't straight forwards (e.g. having enum event type , filter enum).
i vote not override default ravendb behavior, leave different event types own doc collections, , utilize multi-map index.
the raven docs state static indexes preferred on dynamic indexes shouldn't performance concern. docs:
if don't mess tag convention, create more indexes sub-set of events, create map/reduce indexes aggregate counts per event type, , much more.
the index multi-map index , have 2 flavors can take from.
option 1
public class events_all : abstractmultimapindexcreationtask { public events_all() { addmap<newpersonevent>(newpersonevents => newpersonevent in newpersonevents select new { id = newpersonevent.aggregateid }); addmap<neworderevent>(neworderevents => neworderevent in neworderevents select new { id = neworderevent.aggregateid }); } }
option 2 (reflection)
public class events_all2 : abstractmultimapindexcreationtask { public events_all2() { addmapforall<event>(events => @event in events select new { id = @event.aggregateid }); } }
here's illustration test using ravendb.tests.helpers
, shouldly
nuget packages. it's using first illustration index can modify utilize sec well.
public class multimapindextest : raventestbase { private readonly random _random = new random(); [fact] public void getall_hasboth_success() { //arrange const string personname = "jimmy"; double randomcost = _random.next(); var event1 = new newpersonevent(guid.newguid(), personname); var event2 = new neworderevent(guid.newguid(), datetime.now, randomcost); using (var docstore = newdocumentstore()) { docstore.executeindex(new events_all()); using (var sesion = docstore.opensession()) { sesion.store(event1); sesion.store(event2); sesion.savechanges(); } docstore.waitforstaleindexestocomplete(); //act var events = getall(docstore).tolist(); //assert events.shouldnotbeempty(); events.count().shouldbe(2); var newpersonevent = events.firstordefault(x => x newpersonevent) newpersonevent; newpersonevent.shouldnotbe(null); newpersonevent.name.shouldbe(personname); var neworderevent = events.firstordefault(x => x neworderevent) neworderevent; neworderevent.shouldnotbe(null); neworderevent.ordercost.shouldbe(randomcost); } } private ienumerable<event> getall(documentstore docstore) { using (var session = docstore.opensession()) { homecoming session.query<event, events_all>(); } } }
ravendb event-sourcing event-store
No comments:
Post a Comment