I'm trying to reject changes on a newly added entity (expecting breeze to set entityState to detached). Most times it works, but once in a while (mostly after I have already performed an entity create and reject), the rejectChanges call will fail because there is a null reference to the entityAspect.entityManager property.
I am getting my entity instance through "resolve" of ui-router on abstract parent state. Then in the abstract parent controller, I assign that instance to $scope. From then on I deal with $scope.myEntity instead of the resolved variable in my constructor. When I call entity This is my resolve function:
resolve:{
myEntity:function(sharedEntityManager,$stateParams, $q){
return $q.when(sharedEntityManager.getMyEntity($stateParams.entityId))
.then(function(myEntity){
if(!myEntity && myEntity.entityAspect.entityState.isDetached()){
$q.reject();
}
else
{
return myEntity;
}
});
}
}
Then in my parent abstract controller, I call this:
$scope.myEntity = myEntity;
The error I get showing null entityManager...
TypeError: Cannot read property 'isRejectingChanges' of null
at __using (breeze.debug.js:449)
at EntityAspect.proto.rejectChanges (breeze.debug.js:3687)
The error seems to occur only after I have successfully done 1 cycle of creating entity, rejecting that entity. Then when I create another new entity, that new entity somehow goes from "Added" and having an entityManager, to "Detached" and null entityManager. I confirmed that in the resolve function, entityState is "Added", but in the controller constructor, the injected entity from ui-router is now "Detached".
Anyone familiar with this behavior and is there a work around?
Are you sure about the test in the then function? It seems off to me. Do you really mean if(!myEntity && ... or should it be if(!myEntity || ...)
Related
I'm using AsyncCrudAppService Create method for creating entity. Call create method from controller, get newly created entity id, then call Get method of AsyncCrudAppService. But returned data don't sets related entities. I'm having this problem only in this scenario, i mean when i call GetAll(), Get() in other scenarios i'm not getting this problem.
The newly created entity is available after you call SaveChanges method of your unit of work.
var record = new Record() { Name = "lorem ipsum" };
_recordRepository.Insert(record);
CurrentUnitOfWork.SaveChanges();
After that, if you put debugger breakpoint and hover record variable - it is already loaded as DB record.
I have a function that get a Book entity, and checks whether it already exists in the database.
If it already exists, the function needs to update the entity in context.
So when I use the Find function to check whether it exists, the following error is thrown:
Attaching an entity of type 'Books' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
But when I use the Any function to check that, the code work fine.
My guess is that the Find function Attach the entity (to context) but Any not doing it.
Can someone give an explanation please?
The Find function:
public IHttpActionResult PutBook(Books book)
{
if(db.Books.Find(book.id) == null)
{
db.Entry(book).State = EntityState.Modified;
}
.
.
}
The Any function:
public IHttpActionResult PutBook(Books book)
{
if (db.Books.Any(b => b.id.Equals(book.id)))
{
db.Entry(book).State = EntityState.Modified;
}
.
.
}
Sorry if I have English errors.
Yes, Find fetches an entity from the database and attaches it to the context if it's not already in its cache. So at that point there is a Book instance in the context's cache and then you try to attach another instance to it. That's not allowed, because EF's cache is designed as an identity map.
The second snippet obviously doesn't materialize a Book instance: it runs a SQL query that only returns a bool.
In my Grails App, I have bootstrapped an object of a domain class as:
def user1 = new Users(userID: 1, name: "John Doe")
user1.save()
In my dashboard controller i have retrieved the object and modified its property name as:
Users userObj = Users.get((Long) 1)
println(userObj as JSON); // This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
userObj.name = "anonymous"
Now i create a new Users object to retrieve the changed object with same ID 1 as
Users otherUserObj = Users.get((Long) 1) // **Line 2** Is this retrieving from database or from GORM session?
print(otherUserObj as JSON)// This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"anonymous"}
But the value of object in database is not changed. And even when i retrieve the Users object of same id 1 in another controller it gives me the initial object rather than the modified as:
Users userObjAtDifferentController = Users.get(1);
print(userObjAtDifferentController) //This gives me: {"class":"com.prabin.domains.Users","id":1,"name":"John Doe"}
My question is, if the value is not changed in the database, why it gives me the modified object at Line 2 though i have retrieved the object using GORM query (which i guess should retrieve from the database)?
I have also tried using save() after the modification but the result is same.
userObj.save() //doesn't show the changes in database.
My guess is that the object is not being saved to the database because some constraint(s) are invalid. You can determine whether this is the case by replacing your calls to save() with save(failOnError: true). If my guess is correct, an exception will be thrown if saving to the database fails.
When you call the save() method on a domain object, it may not persist in the database immediately. In order to persist the changed value to the database, you would need to do the following.
userObj.save(flush: true)
By using flush, you are telling GORM to persist immediately in the database.
In some cases when validation fails, the data will still not persist in the database. The save() method will fail silently. To catch validation errors as well as save to the database immediately, you would want to do the following
userObj.save(flush:true, failOnError:true)
If validation errors exist, then the GROM will throw ValidationException (http://docs.grails.org/latest/api/grails/validation/ValidationException.html)
You need to consider two things:
If you do save(), it only retains in hibernate session, until you flush it the changes does not persist in database. So, better do save(flush:true, failOnError: true) and put in try/catch block and print exception.
And another important things is, your method in controller needs to be with #Transactional annotation, without it your changes does not persist in database, you will encounter Connection is read-only. Queries leading to data modification are not allowed. exception.
Hope this helps, let me know if your issue is fixed. Happy coding . :)
I am creating a new entity with manager.createEntity("Foo", { a: 1, b: 2});
The problem is Foo has a compound key. Both a and b are its PK values. So if I call createEntity this way, and the entity already exists, I get a MergeStrategy of Disallowed error.
What is the best practice here? Should I call manager.fetchEntityByKey("Foo", [a,b], true) to see if it exists first? Or should I wrap the createEntity call in a try/catch? Or something else?
I would definitely call fetchEntityByKey. The problem with just using createEntity with a try/catch is that this call MAY succeed because the 'new' entity is not yet in the cache because it has not yet been fetched but you will still get an error later when you try to save it because the server will detect that the entity cannot be added because it already exists. Better to always catch errors early ( failfast).
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.