How to deal with whole compensation using Mutiny? - quarkus

Working on Quarkus and SmallRye Mutiny, I don't know how to deal with compensations.
I have a list of employees and I have to update all of them in the database. The Data Access Object (EmployeeDao) has the following method: public Uni<Boolean> update(Long id, String name, Long deptId). It expect to receive the Employee's fields.
Also, I have to return a Uni<Boolean> to notify if all the updates went fine or not. Something as is given below:
public Uni<Boolean> updateEmployees(List<Employee> employees) {
for(Employee employee: employees) {
//TODO: Execute or compensate
}
}
My question is, how can I iterate one by one performing the update process and dealing with compensation?
In case of failure in any employee update process, I'd like to try several times and, after that, if I couldn't update an employee, I have to undo all the employees before returning any response. The idea is to keep the database in a consistent state.
How to deal with whole compensation using Mutiny?

If I understand correctly, you want to execute a set of async operations and combine them.
For this, you can do something like:
List<Uni<?>> list = new ArrayList();
for(Employee employee: employees) {
Uni<Void> uni = update(employee);
list.add(uni);
}
return Uni.combine().all().unis(list)
.with(list -> { /* all employees have been updated */ return true; })
.onFailure().call(failure -> {
Uni<?> uni = compensate();
return uni.onItem().transform(x -> false);
});
The first look collects Unis for each update. Then we combine these. If everything is fine, we are good and return true. If something bad happens, we compensate and return false.

Related

DDD Event Source raise event for created object

I have Category class, that has children property. When creating category, I raise event CategoryCreated in constructor, which registers this event in BaseCategory. Also I have apply method in Category, that applies events to state.
public class Category :BaseCategory
{
public Category(string id, TranslatableString name, DateTime timestamp)
{
Raise(new CategoryCreated(id, name, timestamp));
}
}
public override void Apply(DomainEvent #event)
{
switch (#event)
{
case CategoryCreated e:
this.Id = e.Id;
this.Name = e.Name;
break;
...
Now suppose I want to create Category and add child to it.
var category = new Category("1","2",DateTime.UtcNow);
category.AddChild("some category", "name", DateTime.UtcNow);
foreach(var e in category.UncomittedEvents)
{
category.Apply(e);
}
When adding child I set private property ParentId of newly created category as parent's Id.
public void AddChild(string id, string name,DateTime date)
{
if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(nameof(id));
if (Children.Any(a => a.Id== Id))
throw new InvalidOperationException("Category already exist ");
Raise(new CategoryAdded(Guid.NewGuid().ToString(), this.Id/*parent id*/, name, DateTime.UtcNow));
}
public class CategoryAdded : DomainEvent
{
public CategoryAdded(string id, string parentId, string name, DateTime timestamp) {}
}
The problem is, when applying events, parent id will be null because events were not applied yet and parent's Id property passed as parent id is null:
new CategoryAdded(Guid.NewGuid().ToString(), this.Id /*parent id*/, name, DateTime.UtcNow)
Where is design mistake?
Where and when should be CategoryCreated event raised?
How would you tackle this situation?
Where is design mistake? Where and when should be CategoryCreated event raised? How would you tackle this situation?
OK, this is not your fault. The literature sucks.
CPearson's answer shows a common mechanism for fixing the symptoms, but I think it is important to see what is going on.
If we are applying the "event sourcing" pattern in its pure form, our data model would look like a stream of events:
class Category {
private final List[Event] History;
}
Changes to the current state would be achieved by appending events to the History.
public Category(string id, TranslatableString name, DateTime timestamp) {
History.Add(new CategoryCreated(id, name, timestamp));
}
And queries of the current state would be methods that would search through the event history looking for data.
public Id Id() {
Id current = null;
History.forEach( e -> {
if (e instance of CreatedEvent) {
current = CreatedEvent.Id(e)
}
});
return current
}
The good news is that the design is relatively simple in principle. The bad news is that the performance is dreadful - reading is usually much more common and writing, but every time we want to read something, we have to go skimming through the events to find the answer.
It's not always that bad -- properties that are constant for the entire life cycle of the entity will normally appear in the first event; to get the most recent version of a property you can often enumerate the history backwards, and stop on the first (most recent) match.
But it is still pretty awkward. So to improve query performance we cache the interesting results in properties -- effectively using a snapshot to answer queries. But for that to work, we need to update the cached values (the snapshot) when we add new events to the history.
So the Raise method should be doing two things, modifying the event history, and modifying the snapshot. Modifying the event history is general purpose, so that work often gets shared into a common base class; but the snapshot is specific to the collection of query results we want to cache, so that bit is usually implemented within the "aggregate root" itself.
Because the snapshot when we restore the aggregate from the events stored in our database should match the live copy, this design often includes an Apply method that is used in both settings.
Where is design mistake?
Your Raise(...) method should also call Apply. Remember that your Aggregate is responsible for maintaining a consistent state. Applying events outside of your Aggregate violates that principle.
protected void Raise(DomainEvent #event)
{
this.Apply(#event);
this.UncomittedEvents.Add(#event);
}

Querying single database row using rxjava2

I am using rxjava2 for the first time on an Android project, and am doing SQL queries on a background thread.
However I am having trouble figuring out the best way to do a simple SQL query, and being able to handle the case where the record may or may not exist. Here is the code I am using:
public Observable<Record> createRecordObservable(int id) {
Callable<Record> callback = new Callable<Record>() {
#Override
public Record call() throws Exception {
// do the actual sql stuff, e.g.
// select * from Record where id = ?
return record;
}
};
return Observable.fromCallable(callback).subscribeOn(Schedulers.computation());
}
This works well when there is a record present. But in the case of a non-existent record matching the id, it treats it like an error. Apparently this is because rxjava2 doesn't allow the Callable to return a null.
Obviously I don't really want this. An error should be only if the database failed or something, whereas a empty result is perfectly valid. I read somewhere that one possible solution is wrapping Record in a Java 8 Optional, but my project is not Java 8, and anyway that solution seems a bit ugly.
This is surely such a common, everyday task that I'm sure there must be a simple and easy solution, but I couldn't find one so far. What is the recommended pattern to use here?
Your use case seems appropriate for the RxJava2 new Observable type Maybe, which emit 1 or 0 items.
Maybe.fromCallable will treat returned null as no items emitted.
You can see this discussion regarding nulls with RxJava2, I guess that there is no many choices but using Optional alike in other cases where you need nulls/empty values.
Thanks to #yosriz, I have it working with Maybe. Since I can't put code in comments, I'll post a complete answer here:
Instead of Observable, use Maybe like this:
public Maybe<Record> lookupRecord(int id) {
Callable<Record> callback = new Callable<Record>() {
#Override
public Record call() throws Exception {
// do the actual sql stuff, e.g.
// select * from Record where id = ?
return record;
}
};
return Maybe.fromCallable(callback).subscribeOn(Schedulers.computation());
}
The good thing is the returned record is allowed to be null. To detect which situation occurred in the subscriber, the code is like this:
lookupRecord(id)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Record>() {
#Override
public void accept(Record r) {
// record was loaded OK
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) {
// there was an error
}
}, new Action() {
#Override
public void run() {
// there was an empty result
}
});

Fetch history of records using LINQ

I am using entity framework with repository pattern and unit of work objects..
I have an entity Request with properties "RequestId", "OldRequestId", which can be accessed using requestRepository object.
eg: requestRepostiory.GetAll(), requestRepository.GetFiltered(r=> r.Requestid =10)
If I pass a RequestId, it should retrieve me the specific record.
If the OldRequestId is not null in the retrieved record, it should bring the old request data as well.
It should go on until the OldRequestId is null.
Simple way would be something like this:
public static IEnumerable<Data> GetRecursive(int id)
{
while (true)
{
var tmp = GetFiltered(x => x.Requestid == id);
yield return tmp;
if (tmp.OldRequestId.HasValue)
id = tmp.OldRequestId.Value;
else
yield break;
}
}
Please note, that this code would run make multiple queries towards the database. Performance won't be the best, but it might work for your scenario.

MVC3 Entity Framework Code First Updating Subset Related List of Items

I have a table of data with a list of key value pairs in it.
Key Value
--------------------
ElementName PrimaryEmail
Email someemail#gmail.ca
Value Content/Images/logo-here.jpg
I am able to generate new items on my client webpage. When, I create a new row on the client and save it to the server by executing the following code the item saves to the database as expected.
public ViewResult Add(CardElement cardElement)
{
db.Entry(obj).State = EntityState.Added;
db.SaveChange();
return Json(obj);
}
Now, when I want to delete my objects by sending another ajax request I get a failure.
public void Delete(CardElement[] cardElements)
{
foreach (var cardElement in cardElements)
{
db.Entry(cardElement).State = EntityState.Deleted;
}
db.SaveChanges();
}
This results in the following error.
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
I have tried other ways of deleting including find by id remove and attach and delete but obviously I am approaching in the right fashion.
I am not sure what is causing your issue, but I tend to structure my deletes as follows:
public void Delete(CardElement[] cardElements)
{
foreach (var cardElement in cardElements)
{
var element = db.Table.Where(x => x.ID == cardElement.ID).FirstOrDefault();
if(element != null)
db.DeleteObject(element);
}
db.SaveChanges();
}
although I tend to do database first development, which may change things slightly.
EDIT: the error you are receiving states that no rows were updated. When you pass an object to a view, then pass it back to the controller, this tends to break the link between the object and the data store. That is why I prefer to look up the object first based on its ID, so that I have an object that is still linked to the data store.

Users restrictions for associated data in ASP Membership

I have a site I'm porting to MVC to clean up the code and simplify things. I use the asp membership and profile providers, but I'm wondering if I'm doing this correctly for my situtation. I'm pretty new to MVC, so I wan to get this right in the early stages.
Users are individuals and they are part of larger "institutions" that they either set up or pick at registration. In this case, the institution is a winery. I want the users to be able to view all wines from every winery, but only edit ones that belong to them.
What's the best way to do this? Right now I render the link to the edit field in my index view based on their instution ID and the producer ID. I feel like a data annotation might work better here, but I don't exactly how to implement that for a group of wines. Do I need multiple providers? I use roles to limit the editing, but right now an editor role could manually enter the path of another wine to edit it when that wine doesn't belong to them.
Any pointers here would be awesome. I know I can do it in the controller methods, but I'm looking for the 'right' way to do it. Thanks.
I'm running into the same issue at work right now, and the best proposed solution we have right now is implementing an "ownership" table. You won't be able to solve this using roles.
So basically you have an owner ID, owned object's ID, and the type of objects ID all held together. Lets take an edit request for example. We know that you can only edit the data person X owns, so we have a stored procedure that if a key combination exists in our ownership table where person.ID = owner ID, and item.ID = object ID, and item.TypeID = objectTypeID. If it exists, it goes along performing its edits, otherwise it returns an error.
You can use this scheme to return ownership lists, user validation, and a host of other issues you may come across. You probably won't need the ObjectTypeID if you only have one type's ownership being tracked. Hope this helps!
I figured this out by applying a custom AuthorizeAttribute to the edit, delete, and create actions.
Here is what I ended up doing:
public class ProducerEditAttribute : AuthorizeAttribute
{
private vfContext db = new vfContext();
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
bool bAdmin = filterContext.HttpContext.User.IsInRole("admin");
bool bProdEdit = filterContext.HttpContext.User.IsInRole("producereditor");
bool bProd = filterContext.HttpContext.User.IsInRole("producer");
if (filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (bAdmin)
{
//authorized
}
if (bProdEdit || bProd)
{
//check for current wine belonging to the producer.
Producer currentProd = db.Producers.Find(Profile.GetProfile(filterContext.HttpContext.User.Identity.Name).InstitutionID);
Wine currentWine;
object WineID;
if (filterContext.RouteData.Values.TryGetValue("id", out WineID))
{
currentWine = db.Wines.Find(int.Parse(WineID.ToString()));
if (currentProd.Wines.Contains(currentWine) && bProdEdit)
{
//authorized
}
else if (bProd)
{
var result = new ViewResult();
result.ViewName = "Login.cshtml"; //this can be a property you don't have to hard code it
result.MasterName = "_Layout.cshtml"; //this can also be a property
result.ViewBag.Message = "You do not have permission for add/edit/delete funciontionality. Please request.";
filterContext.Result = result;
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
filterContext.Result = result;
}
}
}
else
{
var result = new ViewResult();
result.ViewName = "Login.cshtml";
result.MasterName = "_Layout.cshtml";
}
}
}
}

Resources