Background:
I have a website (ASP.NET MVC) where users can write/edit/delete a "review".
Doing so needs to kick off a database trigger to update some global statistics on the system.
Database Tables:
Review (parent)
MetaData1 (Review 1 - 0..1 MetaData1)
MetaData2 (Review 1 - 0..1 MetaData2)
MetaData3 (Review 1 - 0..* MetaData3)
So Review is the main table (ReviewId - identity), and the other's are meta data.
The problem:
I have a stored procedure which performs the calculations, which needs to be called whenever a review is created/edited/deleted.
At the moment, i have a trigger which calls the SP on all tables (4 identical triggers). But this results in the stored procedure being executed possibly 4 times when it only needs to be done once.
I can't just put it on Review only, because if a user edits metadata for a review, Review table will not be touched and hence the trigger will not fire.
I need a way of saying "watch all of these tables for activity, when a record is created/edited/deleted, fire off this procedure once."
Any tips/suggestions/ideas?
FYI - i'm using Entity Framework 4 for the CRUD operations, if that matters.
Drop triggers on 3 MetaDataX tables. After saving metadata records, really change something ("last edited" time would be a good candidate) in the Review table.
You may want to write some proxy methods to implement the above logic in Review mapped class to manipulate the metadata objects (and do not use MetaDataX mapped objects directly).
Get rid of the entity framework and triggers. Create a stored procedure that updates four tables, and call that from your web page.
Related
When implementing a system which creates tasks that need to be resolved by some workers, my idea would be to create a table which would have some task definition along with a status, e.g. for document review we'd have something like reviewId, documentId, reviewerId, reviewTime.
When documents are uploaded to the system we'd just store the documentId along with a generated reviewId and leave the reviewerId and reviewTime empty. When next reviewer comes along and starts the review we'd just set his id and current time to mark the job as "in progress" (I deliberately skip the case where the reviewer takes a long time, or dies during the review).
When implementing such a use case in e.g. PostgreSQL we could use the UPDATE review SET reviewerId = :reviewerId, reviewTime: reviewTime WHERE reviewId = (SELECT reviewId from review WHERE reviewId is null AND reviewTime is null FOR UPDATE SKIP LOCKED LIMIT 1) RETURNING reviewId, documentId, reviewerId, reviewTime (so basically update the first non-taken row, using SKIP LOCKED to skip any already in-processing rows).
But when moving from native solution to JDBC and beyond, I'm having troubles implementing this:
Spring Data JPA and Spring Data JDBC don't allow the #Modifying query to return anything else than void/boolean/int and force us to perform 2 queries in a single transaction - one for the first pending row, and second one with the update
one alternative would be to use a stored procedure but I really hate the idea of storing such logic so away from the code
other alternative would be to use a persistent queue and skip the database all along but this introduced additional infrastructure components that need to be maintained and learned. Any suggestions are welcome though.
Am I missing something? Is it possible to have it all or do we have to settle for multiple queries or stored procedures?
Why Spring Data doesn't support returning entity for modifying queries?
Because it seems like a rather special thing to do and Spring Data JDBC tries to focus on the essential stuff.
Is it possible to have it all or do we have to settle for multiple queries or stored procedures?
It is certainly possible to do this.
You can implement a custom method using an injected JdbcTemplate.
I am working on one HRMS application. There is one Transfers workflow in application. As a part of it employee can get transferred from one department/office to other department/office.
Transfers process works as below:
Employee checks for vacancy in application and applies for transfer if vacancy is available. Once employee submits transfer form, it goes for approval to employee's department/office. There are 5 approver in approval flow. In PostgreSQL to achieve 3NF I have decided to create 3 separate tables as below:
1) One for employee's transfer request
2) Transfer request approval request
3) Transfer request approval request details
So in above image you can see for approval request I have created two separate tables i.e. transfer_request_approval and transfer_request_approval_details. transfer_request_approval refers transfer_request_id as FK and transfer_request_approval_details contains transfer_request_approval_id as FK and all 5 approver's record for that particular approval request.
e.g. We have transfer request with id=1, so there would be one row in transfer_request_approval table (e.g. transfer_request_approval_id = 1, transfer_request_id = 1 as FK). In transfer_request_approval_details there would be 5 rows for 5 approver's records.
(Note: approval_status is either Approved or Reject or Rework, note is nothing but user can put some remark. If approver puts rework status it will go back to approver1 again e.g. if Approver5 put rework status it will go to approver1 again for same process. so there would be 10 records for that entire approval request in transfer_request_approval_details table).
Question : Do I really need to have transfer_request_approval_details table or I can include all those approvers records in transfer_request_approval table?
In order to maintain normal form, you need the approval details table separate, otherwise you end up with duplicate values of status for each approver. However, I see no need to have separate transfer_request and transfer_request_approval tables. Just add status to transfer_request and link to apporver_details.
I think you can include all those approvers records in the transfer_request_approval table.
There is no meaning in storing data in a separate 2 tables.
I notice that multiple requests to a record causes writes to be possibly overwritten. I am using Mongo btw.
I have a schema like:
Trip { id, status, tagged_friends }
where tagged_friends is an association to Users collection
When I make 2 calls to update trips in close succession (in this case I am making 2 API calls from client - actually automated tests), its possible for them to interfere. Since they all call trip.save().
Update 1: update the tagged_friends association
Update 2: update the status field
So I am thinking these 2 updates should only save the "dirty" fields. I think I can do that with Trips.update() rather than trip.save()? But problem is I cannot use update to update an association? That does not appear to work?
Or perhaps there's a better way to do this?
The repository in the CommonDomain only exposes the "GetById()". So what to do if my Handler needs a list of Customers for example?
On face value of your question, if you needed to perform operations on multiple aggregates, you would just provide the ID's of each aggregate in your command (which the client would obtain from the query side), then you get each aggregate from the repository.
However, looking at one of your comments in response to another answer I see what you are actually referring to is set based validation.
This very question has raised quite a lot debate about how to do this, and Greg Young has written an blog post on it.
The classic question is 'how do I check that the username hasn't already been used when processing my 'CreateUserCommand'. I believe the suggested approach is to assume that the client has already done this check by asking the query side before issuing the command. When the user aggregate is created the UserCreatedEvent will be raised and handled by the query side. Here, the insert query will fail (either because of a check or unique constraint in the DB), and a compensating command would be issued, which would delete the newly created aggregate and perhaps email the user telling them the username is already taken.
The main point is, you assume that the client has done the check. I know this is approach is difficult to grasp at first - but it's the nature of eventual consistency.
Also you might want to read this other question which is similar, and contains some wise words from Udi Dahan.
In the classic event sourcing model, queries like get all customers would be carried out by a separate query handler which listens to all events in the domain and builds a query model to satisfy the relevant questions.
If you need to query customers by last name, for instance, you could listen to all customer created and customer name change events and just update one table of last-name to customer-id pairs. You could hold other information relevant to the UI that is showing the data, or you could simply hold IDs and go to the repository for the relevant customers in order to work further with them.
You don't need list of customers in your handler. Each aggregate MUST be processed in its own transaction. If you want to show this list to user - just build appropriate view.
Your command needs to contain the id of the aggregate root it should operate on.
This id will be looked up by the client sending the command using a view in your readmodel. This view will be populated with data from the events that your AR emits.
Say that I have a User table in my ReadDatabase (use SQL Server). In a regulare read/write database I can put like a index on the table to make sure that 2 users aren't addedd to the table with the same emailadress.
So if I try to add a user with a emailadress that already exist in my table for a diffrent user, the sql server will throw an exception back.
In Cqrs I can't do that since if I decouple the write to my readdatabas from the domain model, by puting it on an asyncronus queue I wont get the exception thrown back to me, and I will return "OK" to the UI and the user will think that he is added to the database, when infact he will never be added to the read database.
I can do a search in the read database checking if there is a user already in my database with the emailadress, and if there is one, then thru an exception back to the UI. But if they press the save button the same time, I will do 2 checks to the database and see that there isn't any user in the database with the emailadress, I send back that it's okay. Put it on my queue and later it will fail (by hitting the unique identifier).
Am I suppose to load all users from my EventSource (it's a SQL Server) and then do the check on that collection, to see if I have a User that already has this emailadress. That sounds a bit crazy too me...
How have you people solved it?
The way I can see is to not using an asyncronized queue, but use a syncronized one but that will affect perfomance really bad, specially when you have many "read storages" to write to...
Need some help here...
Searching for CQRS Set Based Validation will give you solutions to this issue.
Greg Young posted about the business impact of embracing eventual consistency http://codebetter.com/gregyoung/2010/08/12/eventual-consistency-and-set-validation/
Jérémie Chassaing posted about discovering missing aggregate roots in the domain http://thinkbeforecoding.com/post/2009/10/28/Uniqueness-validation-in-CQRS-Architecture
Related stack overflow questions:
How to handle set based consistency validation in CQRS?
CQRS Validation & uniqueness