Language
C#
Article For
3.0 3.5 4.0 4.1 5.1 5.3

Session: How to Subscribe to Events

The concept of events provides users with a mechanism to perform custom actions in response to operations taken in a session.

The event is invoked when a particular action is executed on an entity or querying is performed.

Subscribing to an event

Subscribing an event can be done in the DocumentStore object, which will be valid for all future sessions or subscribing in an already opened session with session.advanced() which will overwrite the existing event for the current session.

beforeStoreListener

This event is invoked as a part of saveChanges but before it is actually sent to the server.
It should be defined with this signature:

public void addBeforeStoreListener(EventHandler<BeforeStoreEventArgs> handler);

public void removeBeforeStoreListener(EventHandler<BeforeStoreEventArgs> handler);
Parameters Type Description
handler EventHandler<BeforeStoreEventArgs> handle this event

The class BeforeStoreEventArgs:

public BeforeStoreEventArgs(InMemoryDocumentSessionOperations session, String documentId, Object entity);

public class BeforeStoreEventArgs
{
    private IMetadataDictionary _documentMetadata;
    private final InMemoryDocumentSessionOperations session;
    private final String documentId;
    private final Object entity;

    //getters and setters (omitted for brevity)
}

Example

Say we want to discontinue all of the products that are not in stock.

private void onBeforeStoreEvent(Object sender, BeforeStoreEventArgs args) {
    if (args.getEntity() instanceof Product) {
        Product product = (Product) args.getEntity();
        if (product.getUnitsInStock() == 0) {
            product.setDiscontinued(true);
        }
    }
}

After we subscribe to the event, every stored entity will invoke the method.

// subscribe to the event
store.addBeforeStoreListener(this::onBeforeStoreEvent);

try (IDocumentSession session = store.openSession()) {
    Product product1 = new Product();
    product1.setName("RavenDB v3.5");
    product1.setUnitsInStock(0);

    session.store(product1);

    Product product2 = new Product();
    product2.setName("RavenDB v4.0");
    product2.setUnitsInStock(1000);
    session.store(product2);

    session.saveChanges();  // Here the method is invoked
}

beforeDeleteListener

This event is invoked by delete(id) or delete(entity). It is only executed when saveChanges() is called, but before the commands are actually sent to the server.
It should be defined with this signature:

public void addBeforeDeleteListener(EventHandler<BeforeDeleteEventArgs> handler);

public void removeBeforeDeleteListener(EventHandler<BeforeDeleteEventArgs> handler);
Parameters Type Description
handler EventHandler<BeforeDeleteEventArgs> handle this event

The class BeforeDeleteEventArgs:

public BeforeDeleteEventArgs(InMemoryDocumentSessionOperations session, String documentId, Object entity);

public class BeforeDeleteEventArgs
{
    private IMetadataDictionary _documentMetadata;
    private final InMemoryDocumentSessionOperations session;
    private final String documentId;
    private final Object entity;

    //getters and setters (omitted for brevity)
}

Example

To prevent anyone from deleting entities we can create a method as follows:

private void onBeforeDeleteEvent(Object sender, BeforeDeleteEventArgs args) {
    throw new NotImplementedException("Sample");
}

and subscribe it to the session:

// subscribe to the event
store.addBeforeDeleteListener(this::onBeforeDeleteEvent);

// open a session and delete entity
try (IDocumentSession session = store.openSession()) {
    Product product = session.load(Product.class, "products/1-A");

    session.delete(product);
    session.saveChanges(); // NotImplementedException will be thrown here
}

afterSaveChangesListener

This event is invoked after the saveChanges is returned.
It should be defined with this signature:

public void addAfterSaveChangesListener(EventHandler<AfterSaveChangesEventArgs> handler);

public void removeAfterSaveChangesListener(EventHandler<AfterSaveChangesEventArgs> handler);
Parameters Type Description
handler EventHandler<AfterSaveChangesEventArgs> handle this event

The class AfterSaveChangesEventArgs:

public AfterSaveChangesEventArgs(InMemoryDocumentSessionOperations session, String documentId, Object entity);

public class AfterSaveChangesEventArgs
{
    private IMetadataDictionary _documentMetadata;
    private final InMemoryDocumentSessionOperations session;
    private final String documentId;
    private final Object entity;

    //getters and setters (omitted for brevity)
}

Example

If we want to log each entity that was saved, we can create a method as follows:

private void onAfterSaveChangesEvent(Object sender, AfterSaveChangesEventArgs args) {
    if (log.isLoggable(Level.INFO)) {
        log.info("Document " + args.getDocumentId() + " was saved");
    }
}

beforeQueryListener

This event is invoked just before the query is sent to the server. It should be defined with this signature:

public void addBeforeQueryListener(EventHandler<BeforeQueryEventArgs> handler);

public void removeBeforeQueryListener(EventHandler<BeforeQueryEventArgs> handler);
Parameters Type Description
handler EventHandler<BeforeQueryEventArgs> handle this event

The class BeforeQueryEventArgs:

public class BeforeQueryEventArgs
{
    private final InMemoryDocumentSessionOperations session;
    private final IDocumentQueryCustomization queryCustomization;

    //getters (omitted for brevity)
}

Example I

If you want to disable caching of all query results, you can implement the method as follows:

private void onBeforeQueryEvent(Object sender, BeforeQueryEventArgs args) {
    args.getQueryCustomization().noCaching();
}

Example II

If you want each query to wait for non-stale results you can create an event as follows:

private void onBeforeQueryEvent(BeforeQueryEventArgs args) {
    args.getQueryCustomization().waitForNonStaleResults(Duration.ofSeconds(30));
}

beforeConversionToDocumentListener

This event is invoked before conversion of an entity to blittable JSON document. E.g. it's called when sending a document to a server.
It should be defined with this signature:

public void addBeforeConversionToDocumentListener(EventHandler<BeforeConversionToDocumentEventArgs> handler);

public void removeBeforeConversionToDocumentListener(EventHandler<BeforeConversionToDocumentEventArgs> handler);
Parameters Type Description
handler EventHandler<BeforeConversionToDocumentEventArgs> handle this event

The class BeforeConversionToDocumentEventArgs:

public BeforeConversionToDocumentEventArgs(InMemoryDocumentSessionOperations session, String id, Object entity);

public class BeforeConversionToDocumentEventArgs
{
    private String _id;
    private Object _entity;
    private InMemoryDocumentSessionOperations _session;

    //getters (omitted for brevity)
}

Example

private void onBeforeConversionToDocument(Object sender, BeforeConversionToDocumentEventArgs args) {
    if (args.getEntity() instanceof Item) {
        Item item = (Item) args.getEntity();
        item.setBefore(true);
    }
}

afterConversionToDocumentListener

This event is invoked after conversion of an entity to blittable JSON document.
It should be defined with this signature:

public void addAfterConversionToDocumentListener(EventHandler<AfterConversionToDocumentEventArgs> handler);

public void removeAfterConversionToDocumentListener(EventHandler<AfterConversionToDocumentEventArgs> handler);
Parameters Type Description
handler EventHandler<AfterConversionToDocumentEventArgs> handle this event

The class AfterConversionToDocumentEventArgs:

public AfterConversionToDocumentEventArgs(InMemoryDocumentSessionOperations session, String id, Object entity, Reference<ObjectNode> document);

public class AfterConversionToDocumentEventArgs
{
    private String _id;
    private Object _entity;
    private Reference<ObjectNode> _document;
    private InMemoryDocumentSessionOperations _session;

    //getters (omitted for brevity)
}

Example

private void onAfterConversionToDocument(Object sender, AfterConversionToDocumentEventArgs args) {
    if (args.getEntity() instanceof Item)
    {
        Item item = (Item) args.getEntity();
        item.setAfter(true);
    }
}

beforeConversionToEntityListener

This event is invoked before conversion of a JSON document to an entity. E.g. it's called when loading a document.

It takes the argument BeforeConversionToEntityEventArgs, that consists of a JSON document, its ID and type, and the session instance.

public void addBeforeConversionToEntityListener(EventHandler<BeforeConversionToEntityEventArgs> handler);

public void removeBeforeConversionToEntityListener(EventHandler<BeforeConversionToEntityEventArgs> handler);
Parameters Type Description
handler EventHandler<BeforeConversionToEntityEventArgs> handle this event

public class BeforeConversionToEntityEventArgs{

    private String _id;
    private Class _type;
    private Reference<ObjectNode> _document;
    private InMemoryDocumentSessionOperations _session;

    //getters (omitted for brevity)
}

private void onBeforeConversionToEntity(Object sender, BeforeConversionToEntityEventArgs args) {
    if (args.getId() == "item/1-A")
    {
        if (log.isLoggable(Level.INFO)) {
            log.info("Document " + args.getId() + " has found");
        }
    }
}

afterConversionToEntityListener

This event is invoked after conversion of a JSON document to an entity. It takes the argument AfterConversionToEntityEventArgs, that consists of a JSON document, its ID, the session instance and a converted entity.

public void addAfterConversionToEntityListener(EventHandler<AfterConversionToEntityEventArgs> handler);

public void removeAfterConversionToEntityListener(EventHandler<AfterConversionToEntityEventArgs> handler);
Parameters Type Description
handler EventHandler<AfterConversionToEntityEventArgs> handle this event

public class AfterConversionToEntityEventArgs {

    private String _id;
    private ObjectNode _document;
    private Object _entity;
    private InMemoryDocumentSessionOperations _session;

    //getters (omitted for brevity)
}

private void onAfterConversionToEntity(Object sender, AfterConversionToEntityEventArgs args) {
    if (args.getEntity() instanceof Item) {
        Item item = (Item) args.getEntity();
        item.setAfter(true);
    }
}