I have a document model with the field “year”. I want to make this field unique among all the documents, so that a user cannot create another document with the same year, or update an existing document to have a duplicate year with another existing one. Is there a simple way to do this?
I tried creating a custom validation rule (by implementing ICustomCondition). For this, I need to get the DocumentReference of the current document (document which is being created/updated) in the method check() but I don’t see it.
The only way to make this reliable is to use a database unique constraint. Create a transactional after save event listener to extract the value of the year field and the id from the document and put this into a custom table that has a unique constraint on the column for the value of the year field.Be prepared to handle unique constraint violations (for example report a http 409 Conflict to your rest client).
Moin,
in the create case of a document you don’t have a document reference at hand, because it is not created at that point yet and therefore is null.
In the update case of a document you could set the document id by adding an eventlistener:
@Component
public class DocumentUpdateEventListener {
@EventListener
public void beforeUpdateListener(DocumentBeforeUpdateEvent event) {
event.getUpdatedDocument().setId(event.getDocumentReference().getDocumentId());
}
}
By this, you have the document id available in the CustomCondition.
As you set the tag of this ticket to Modeling, I feel that we should also have the modeling perspective.
If you used a composed data model (CDM) you can use a validation rule on this CDM to validate if the linked documents have a unique year. If you created all your new documents on the CDM, they would be automatically linked and validated when you tried to save the CDM.
The problem is that the user flow is a bit odd. You could have a separate overview for viewing the documents. If you omit the add button, the user is forced to create new documents on the CDM. If you make the year field in the form for this overview read-only then then user cannot change it. The problem is that the CDM is then accessed via a seperate CDM Overview in a different tab in your application.
Thanks for the suggestion, I intend to create a new transient field to contain documentReference instead id.
My answer is a bit late, but I was also searching for a way to make things unique across documents (of the same model).
As it doesn’t seem to be (easily) possible with A12 modeling, doing it in the database seems to be the most efficient option.
But it’s not necessary to do this in an event listener or create a a custom table.
As A12 documents are now stored as JSON (instead of XML) it’s possible to create a unique constraint based on one (or more) fields of the document (for a specific model).
The question would be, how A12 handles the database error if a document is inserted (or updated) that fails the unique constraint validation.
@thomas-soft-grove Given different document models and needing to create a unique constraint for documents of model Foo having a unique field /Bar/Baz in those documents how can one create a unique constraint that won’t be violated for all documents of other models since they won’t have the field /Bar/Baz?
You add a WHERE clause to the index definition:
create unique index on document (...)
where model_name = 'Contract';
The ... would be the expression that extracts the field that is required to be unique across all documents for that model.