entity level validator not triggered - breeze

I've observed that when I'm adding an entity to a collection of another entity, the validator for the second entity is not called.
I expected that adding to a child collection triggers entity level validation on the parent when savechanges is called.
I can't write a test right now, but if needed I'll would write it this afternoon.
Is this the expected behaviour or a bug?
entity.OrderLine().arrayChanged.subscribe(function (args) {
console.log(args);
if (args.added && args.added.some(function (element) {
console.log(element.entityAspect.entityState.name);
return !(element.entityAspect.entityState.isUnchanged()
|| element.entityAspect.entityState.isDeleted());
})) {
console.log("modifico");
entity.entityAspect.setModified();
}
if (args.removed && args.removed.some(function (element) {
console.log(element.entityAspect.entityState.name);
return !element.entityAspect.entityState.isAdded();
})) {
console.log("modifico");
entity.entityAspect.setModified();
}
});

The parent is not changed automatically by the addition of a child because no data property of the parent changes. That is the technical reason.
Sometimes (often?) the model semantics say that the parent is changed by any addition/deletion/change-to a child. That is not always true which is why Breeze doesn't propagate the change automatically. But it is often true ... and I think it would be a good idea for Breeze to support this for you if you specify this as desired behavior in the metadata. You are not alone in wanting this.
I've added a User Voice suggestion for this idea; please vote for it if it (and add your comments) if it matters to you.
Meanwhile, in an entity initializer you can subscribe to changes in the parent collection and to the items of that collection and have them set the parent to the "Modified" state (parent.entityAspect.setModified()). This will have to do for now I'm afraid.

Related

Realm and RxSwift: A field change listener updating a field in the same object fails

I have a way to work around this, but would like to know generally if this is just an inappropriate pattern for Realm and RxSwift or if it reflects a bug in the underlying framework interaction. Here's what I'm doing. I have set up a change listener on one Realm entity (call that entity A; this is only ever a single instance or record of this type of Realm object) looking for changes, except for a few special fields in entity A. I use:
extension Observable where Element: Object {
/// Observe changes to object *except* for specific fields.
static func from(object: Element, emitInitialValue: Bool = true,
exceptForProperties: [String]) -> Observable<Element> {
return Observable<Element>.create { observer in
if emitInitialValue {
observer.onNext(object)
}
let token = object.observe { change in
switch change {
case .change(let changedProperties):
if changedProperties.contains(where: {
return exceptForProperties.contains($0.name)
}) {
// if change property is an excepted one, just return
return
}
observer.onNext(object)
case .deleted:
observer.onError(RxRealmError.objectDeleted)
case .error(let error):
observer.onError(error)
}
}
return Disposables.create {
token.invalidate()
}
}
}
}
When I detect a change in one of the non-special fields in entity A, I update the special fields in entity A (e.g., this includes a "dirty" flag indicating I need to upload the Realm entity).
What I'm finding is that when I follow this sequence:
1) Change one of the non-special fields in the Realm entity A
2) Do a Realm write with some other Realm entity, entity B (a different type of Realm object)
3) At exactly the point where that Realm write in 2) starts, that triggers the change listener for entity A. And tries do another (nested) Realm write, which of course fails with a Realm exception.
Is this just an inappropriate pattern to use (having a field change listener update that same entity) or is something else going on? Thanks.
It's an inappropriate pattern. "Changes in A cause A to change" is inherently circular and you want to strive for a unidirectional data flow.
You say in your question "When I detect a change in one of the non-special fields in entity A..." and that raises the question, what changed the non-special field and while it was changing the non-special field, why didn't it also make the other necessary changes?
There are specific reasons to change any particular field in A. For each field, you should outline what those reasons are, and they should be doing the changing.

What's the differences between EntityState.Added and Add()?

I'm recently using this to add entity EF to my DB:
ctx.Entry(payment).State = payments.ID == 0 ? EntityState.Added : EntityState.Modified;
Instead of the common:
ctx.Payments.Add(payments);
The second is nice because I can choose if add or delete.
What's the real difference between the first and the second approch? And why there isn't a straightforward for update item? Such as:
ctx.Payments.Update(payments);
Which will "mirror" the EntityState.Modified one?
This is the code I'm using, setting a ViewModel from my MVC Action/Controller to my EF context:
IList<Payments> newPayments = activityViewModel.Payments.Select(p => mapper.Map<PaymentViewModel, Payments>(p)).ToList();
foreach (var payments in newPayments)
{
ctx.Entry(payments).State = payments.ID == 0 ? EntityState.Added : EntityState.Modified;
ctx.Payments.Add(payments);
}
ctx.SaveChanges();
There is no difference between adding a detached entity by setting its state vs. calling Add.
You can see in InternalEntityEntry.cs (wrapped by DbEntityEntry) that setting the state to Added just ends up calling InternalSet.Add. You can see in DbSet`.cs that calling Add also just ends up calling InternalSet.Add. They differ a bit in their preconditions, but in your case, the preconditions of both are met.
The nice part about the first approach, in your case, is that the same bit of code can either add an entity, or attach it and mark it as modified. As you noted, there is no single-method alternative for setting the state to Modified.
The second is nice because I can choose if add or delete.
You can also set the state to Deleted, so that is not an advantage of either over the other.
And why there isn't a straightforward for update item?
Likely because the only use case for it is when you're doing something strange, from EF perspective. Detaching, serialising, modifying, de-serialising and re-attaching entities may be the norm in your framework, but from EF perspective, those are advanced low-level operations with a somewhat enlarged risk of things going wrong. For instance, when your model contains any modifiable property also used for concurrency checks, the fact that your serialisation-deserialisation loses the property's original value means that the concurrency check is sure to fail.

Extending entities on a per view basis with breeze.js in SPA

Trying to figure out how to extend entities that I query from breeze.js on a per-view basis in a single page application. Right now breeze is acting as the gate-keeper when it comes to extending (a.k.a materializing) them and I’m wondering what other options are available to allow me to do this. I initially started with knockout’s mapping plugin but found that it refused to handle child collections for some reason so I moved to using breeze’s constructor function and initializer methodology. The problem with this is that you can only define one custom "model" for an entity. I am looking for approaches that would allow a custom "model" of an entity on a per-view basis. I’ve already ruled out multiple managers. Querying meta-data multiple times is a huge unnecessary hit just to get this working.
This diagram visualizes what I’m trying to achieve. Both View 1 and View 2 ultimately query Entity B and both views require their own specific customization of the "model" of Entity B. Since View 1 loads first it’s custom "model" of Entity B "wins" and View 2 doesn’t have the opportunity to customize it. When View 2 eventually runs it’s query, any entities of type B that were already loaded by View 1 will have the custom "model" that View 1 defined which will make View 2 explode during binding. Any entities not already loaded by View 1 will now have View 2's custom "model" which would eventually crash View 1 if it could even get that far down the road. See this post.
My thought was to manually create my own custom "model" for each view that has an Entity observable and I could then iterate over every entity returned from a breeze query and new up this custom "model" and pass in the current item, assigning it to the Entity property. I don't really want to do this because I now have I'll have tons of iteration code everywhere and I'd much rather use knockout's mapping plugin. Pseudo code:
function view1EntityBModel(entity) {
var self = this;
self.Entity = ko.observable(entity);
self.myCustomProperty = ko.observable();
...
}
function view2EntityBModel(entity) {
var self = this;
self.Entity = ko.observable(entity);
self.isExpanded = ko.observable(false);
...
}
I was wondering if there are any other solutions available to achieve this same goal?
Or even better does anyone know how to make the knockout mapping plugin working on child collections?
I think the problem here is that by the time the mapping plugin gets a-hold of the breeze data the Children collection has already been converted into an observable array and the mapping plugin doesn't know that it needs to "call" the Children() property in order to get back a list.
var categoryMapper = {
create: function (options) {
return new categoryModel(options.data);
},
Children: { // this doesn't fire for the children
create: function (options) {
return new categoryModel(options.data);
}
}
}
function categoryModel(data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
}
Guessing that you've moved on by now, but thought I'd offer a recommendation for others in a similar position.
Our solution to a similar situation borrows from the breeze.js TempHire sample solution which implements a client side repository/uow pattern. The solution uses an EntityMananagerProvider to manage multiple EntityManagers. The EntityMananagerProvider makes a single call for metadata, which is then used to create new child EntityManagers - satisfying your concern regarding multiple metadata calls. You can then use custom models/uow/repositories to extend the child manager for specific views.

Emberjs - Temporary disable property changes notification

Is there any simple way to achieve a temporary disabling of notifications of an object property or properties?
I know you can defer them with beginPropertyChanges() and endPropertyChanges() but I don't want those changes to be notified at all until I explicitly enable them.
Thank you in advance.
Use case:
I have to set a property of an object (A) with another object (B). Properties of B are being observed by several methods of other objects. At some time the B object's data gets cleared and the observers get notified, later an HTTP response sets them with something useful. I would not want the observers get notified when clearing the object because the properties values are not valid at that moment.
Ember doesn't support suspending notifications. I would strongly suggest against toying with the private APIs mentioned in the above comments.
I wonder why you bother clearing the object's data prior to the HTTP request? Seems strange.
Using a flag will cause the computed to still trigger.
The best I've come up with is to override the computed with the last known value. Later you can enable it by setting the computed property definition again.
let _myComputedProperty = Ember.computed('foobar', function() {
let foobar = this.get('foobar');
console.log('myComputedProperty triggered >', foobar);
return '_' + foobar + '_';
});
Controller.extend({
turnOffComputed: function() {
let myComputedProperty = this.get('myComputedProperty');
this.set('myComputedProperty', myComputedProperty);
},
turnOnComputed: function() {
this.set('myComputedProperty', _myComputedProperty);
}
})
Full example: Conditional binding for a computed property
This is an old question, but it appears high in Google search for suspending observers, so I would comment.
There are evident use cases for such a feature, for example, an enum property of an object is represented by a list box and the object may change. If the list box is used to request property changes from the server and to set the new value on success, the natural way to do things is to use a controller property with the list box, set that property to the object property when the object changes, and observe it to make requests to the server. In this case whenever the object changes the observer will receive an unwanted notification.
However, I agree that these use cases are so diverse that there is no way Ember can support them.
Thus, a possible work around is to declare a variable in the controller and use it whenever you change a property so that you react only to changes made by the User:
doNotReact: false,
updateManually: function() {
this.doNotReact = true;
Ember.run.scheduleOnce('actions', this, function() {
this.doNotReact = false;
});
............
this.set('something', somevalue);
............
},
onChange: function() {
if (this.doNotReact) return;
...............
}.observes('something')
The value of doNotReact will be reset after the observer gets a chance to run. I do not recommend to reset the stopper variable in the observer since it will not run if you set the property to the same value it already has.

Cancel/Block the save of a domain object based on some criteria?

i have a need to block or cancel a save of a domain object based on some property.
Can this be done in a constraint?
Example:
An 'Order' domain object has a state of 'invoiced' then the order should not be able to be updated anymore..
Any suggestions on how to tackle this?
I see no reason why you couldn't simply use a constraint for this (as you suggested). Something like this should do it
class Order {
String state
static constraints = {
state(validator: {stateValue, self ->
// only check state if this object has already been saved
if (self.id && stateValue == 'invoiced') {
return false
}
})
}
}
If for some reason you can't use a constraint, here are a couple of alternative suggestions:
Meta-Programming
Use Groovy's method-interception capabilities to intercept calls to save(). Your interceptor should only forward the call to the intercepted save() if the order does not have an invoiced state.
There are some good examples of how to do this in the Programming Groovy book
GORM Events
GORM provides a number of events that are triggered during a persisted objects lifecycle. It may be possible in the beforeUpdate or beforeValidate events to prevent updating the object (I guess throwing an exception would work)

Resources