Skip to content
martypitt edited this page Apr 13, 2012 · 1 revision

This page will step you through the steps required to get a simple cross-store domain model working.

Here are the classes we'll be persisting:

@Entity
public class Author implements RelatedEntity {

	@Id @GeneratedValue(strategy=GenerationType.AUTO)
	private Long id;
	
	@Transient @RelatedDocument
	private Book book;
	
	private String name;
}

@Document
public class Book {

	@Id
	private String id;

	private Author author;

	private String title;
}

So we have a JPA entity called Author, and a MongoDB document called Book. Note that there's a cyclical reference between Author and Book.

Setting up your entities & repositories

Swap JpaRepository for CrossStoreJpaRepostory

A repository which stores entities that references other documents must now use the CrossStoreJpaRepository<T,ID> interface. This is a simple marker interface which extends JpaRepository<T.ID>:

public interface AuthorDAO extends CrossStoreJpaRepository<Author, Long> {

}

Tag with @RelatedDocument and @Transient

Fields in entities which are to be persisted as documents in Mongo need to be annotated with @Transient @RelatedDocument:

@Transient @RelatedDocument
private Book book;

Note: This is different from Spring Data, where the @Transient annotation is not required.

Support for RelatedEntities

This project adds support for related entities - ie., A JPA entity stored as a reference on a MongoDB document. In order to get this going, you simply need to implement RelatedEntity on the domain class that appears on your document.

@Entity
public class Author implements RelatedEntity {
}

RelatedEntity is a marker interface (no code required).

Setting up the Spring environment

First up, ensure that your Spring context has AspectJ support enabled:

<aop:aspectj-autoproxy />

Also, you need to enable component scanning for the com.mangofactory.crossstore packages:

<context:component-scan base-package="com.mangofactory.crossstore" />

Finally, you need to wire up the entity mappers that enable RelatedEntity support:

<bean id="relatedEntityReader" class="com.mangofactory.crossstore.converters.RelatedEntityReader" />
<bean id="relatedEntityWriter" class="com.mangofactory.crossstore.converters.RelatedEntityWriter" />
<mongo:mapping-converter id="mappingConverter" 
	base-package="com.mangofactory">
	<mongo:custom-converters>
		<mongo:converter ref="relatedEntityReader" />
		<mongo:converter ref="relatedEntityWriter" />
	</mongo:custom-converters>
</mongo:mapping-converter>

That's it - from here you should be good to go.

Saving and loading cross-store dependencies happens transparently from here.

Here's a simple example that shows it all working:

@Autowired
private BookDAO bookDAO;
@Autowired
private AuthorDAO authorDAO;

public void example()
{
	// First up, create the objects and save.
	// Author will be saved to a db via JPA, and Book to a MongoDB collection.
	Author author = Author.withNameAndBook("Josh Bloch", "Effective Java");
	authorDAO.save(author);
	
	// If we want to, we can fetch the book back from mongo:
	Book book = bookDAO.findOne(bookId);
	
	// Update the title
	author.getBook().setTitle("Effective Java, second edition");
	authorDAO.save(author);
	
	Author fetchedAuthor = authorDAO.findOne(author.getId());
	assertThat(author.getBook(), notNullValue());
	assertThat(author.getBook().getTitle(), equalTo("Effective Java, second edition"));
}

There are more tests available in the project.