I would like to know if there is a way to override an existing relational model after a fetch.
Example:
I have a method on an API that returns a random model. So I created a new instance of the model client side and performed a fetch:
var x = new MyModel();
x.url = 'random';
x.fetch();
// If it exists it will throw "Uncaught Error: Cannot instantiate more than one Backbone.RelationalModel with the same id per type! "
This example works fine unless I have already have an instance of that model client side. Is there a way for me to determine if that model already exists client side after a fetch and update that model instead?
backbone-relational has a built in method for this in 'findModel' which returns the model if found:
backbone-relational docs
You should be able to add a conditional statement to catch
if( x = MyModel.findModel({id: id}) ) {}
else {
x = new myModel();
}
Related
Hiy!
I want all objects(rows in Test Type) with ModelService
So I could iterate through collection and update a Single row (object)'s attribute with new value
I see getModelService.create(TestModel.class) and getModelService.save()
but will they not create a new object/row rather than update a existing object?right
I don't want to create a new one rather selecting one of the existing matching my criteria and update one attribute of that
can somebody help with List<TestModel> testModels = getModelService.get(TestModel.class) will that return me all rows (collection) of Test Type/Table?
unfortunately I can't test it so need help
Actually I am in validateInterceptor ... and on the basis of this intercepted model changed attribute value I have to update another model attribute value...
thanks
ModelService.create(new TestModel.class) will create a single instance of the specified type and attach it to the modelservice's context.
But it will only be saved to the persistence store when you call modelService.save(newInstance)
ModelService.get() returns a model object but expects a Jalo object as input, (Jalo being the legacy persistence layer of hybris) so that won't work for you.
To retrieve objects you can either write your own queries using the FlexibleSearchService or you can have a look at the DefaultGenericDao which has a bunch of simple find() type of methods.
Typically you would inject the dao like e.g.:
private GenericDao<TestModel> dao;
[...]
public void myMethod()
{
List<TestModel> allTestModels = dao.find();
[...]
}
There are a lot more methods with which you can create WHERE type of statements to restrict your result.
Regarding ValidateInterceptor:
Have a look at the wiki page for the lifecycle of interceptors:
https://wiki.hybris.com/display/release5/Interceptors
It's not a good idea to modify 'all' objects of a type while being an interceptor of that type.
So if you're in an interceptor declared for the Test item type, then don't try to modify the items there.
If you happen to be in a different interceptor and want to modify items of a different type:
E.g. you have Type1 which has a list of Type2 objects in it and in the interceptor for Type1 you want to modify all Type2 objects.
For those scenarios you would have to add the instances of Type2 that you modify to the interceptor context so that those changes will be persisted.
That would be something like:
void onValidate(Test1 model, InterceptorContext ctx) throws InterceptorException
{
...
List<Type2> type2s = dao.find();
for (Type2 type2 : type2s)
{
// do something with it
// then make sure to persist that change
ctx.registerElementFor(type2, PersistenceOperation.SAVE);
[...]
}
}
First of all - i think it's not a good idea, to create/update models in any interceptor, especially in 'validation' one.
Regarding your question:
ModelService in most of the cases works with single model, and
designed for create/update/delete operations.
To retreive all models of certain type, you have to use FlexibleSearchService
Then to update each retrieved TestType model, you can use ModelService's save method.
A query to retreive all TestType models will look like:
SELECT PK FROM {TestType}
You could simply use the Flexible Search Service search by example method, and the model service to save them all. Here is an example using Groovy script, with all products :
import java.util.List
import de.hybris.platform.core.model.product.ProductModel
import de.hybris.platform.servicelayer.search.FlexibleSearchService
import de.hybris.platform.servicelayer.model.ModelService
FlexibleSearchService fsq = spring.getBean("flexibleSearchService")
ModelService ms = spring.getBean("modelService")
ProductModel prd = ms.create(ProductModel.class)
List<ProductModel> products = fsq.getModelsByExample(prd)
//Do Whatever you want with the objects in the List
ms.saveAll(products)
I can't get Django to serialize the AL_NODE as a modelserializer. Is it possible to serialize AL_NODEs?
Here is my code:
class UserSecuritySelectionModelSerializers(serializers.ModelSerializer):
class Meta:
model = UserSecuritySelectionModel()
fields = ('hasChildNode', 'classificationNames', 'tgtWeight','currWeight','SSM','ext_model_id')
Here is a sample of the data and how it is structured in the database:
Code in my views.py
if request.is_ajax() and id is not None:
rootNode = UserSecuritySelectionModel.objects.get(SSM_id=id, classificationNameNode__isnull=True)
if not rootNode.is_root():
node = rootNode.get_root()
data = serializers.serialize('json', node, use_natural_foreign_keys=True)
return JsonResponse(data, safe=False)
userSelectionModelSerializer = UserSecuritySelectionModelSerializers(rootNode)
#data = serializers.serialize('json', [rootNode], use_natural_foreign_keys=True)
return JsonResponse (userSelectionModelSerializer.data, status=201, safe=False)
You say it's not working but you haven't included any details about the error you are getting. This makes everything here a guess.
You should just be setting the model reference to a class, not actually creating an instance of the model
model = UserSecuritySelectionModel()
# should be
class Meta:
model = UserSecuritySelectionModel
Next, I think you should explicitly pass in the instance just to be safe. It's not required, but it makes your intention clear:
UserSecuritySelectionModelSerializers(instance=rootNode)
Third, just return a standard Response, not a JsonResponse, DRF will do the content negotiation for you. That is why you are using it.
return Response(MyLongSerializer(instance=root).data)
Finally, is there any reason for sending a 201? You do not appear to be creating anything in the view. If you are, then send it like this:
return Response(..., status=HTTP_201_CREATED)
From the docs:
Class actions return empty instance (with additional properties
below). Instance actions return promise of the action
The documentations however doesn't clearly differentiate between Class actions and Instance actions. Could you please point out differences with a good example if possible?
When you create a new resource type, you supply it a list of actions that can be performed. By default, these are get, save, query, delete, and remove (I think remove is just an alias of delete). You can add your own, as it says in the docs.
The thing about class vs instance is in regard to something it does for convenience of use. "Class actions" refers to calling the action off the resource class that you create itself, kinda like static or shared methods in some other languages. This is useful as an entry point for getting, querying, or saving an instance of your resource when you don't already have the instance. get and query are the clearest example of this. If you have a Car resource, and you need to retrieve it, where do you start? With a class action, of course, such as get.
Now, when your resource class retrieves an existing instance, or you create a new instance, $resource will extend your instance with the actions defined for your resource, but prefix them with a $ so they don't collide with fields on your resource. These are your instance actions. The difference between instance and class, is instance is done in the context of the current instance. So if you get an instance, but then call $save or $delete on that instance, it will save or delete that instance specifically. Instance actions are there simply for convenience.
So they are pretty much the same, the difference is the context in which they are being used.
function($resource) {
// first let's define a new resource for car, where all cars have an id field
// calling $resource will create a new resource class that can be used to
// create, retrieve, update, or delete instances
// this is usually done as a service and injected into controllers as needed.
var Car = $resource('/api/car/:id', {id: '#id'});
// the car class we just created has some class actions that can help you query for or get car instances
// let's create a new instance of a car and save it
var newCar = new Car({make: 'Toyota', model: 'Prius'});
// the prototype of Car includes the instance action versions of the actions defined for the resource. below, $save is your instance action
newCar.$save(); // server will respond with the object after it's saved, so we can now access the id. let's say the id it returned is 24, we'll reference this value later.
// now, let's imagine some time later we want to retrieve the car and update it
// Car.get is a class action that requests the resource from the server, parses the JSON into an object, and merges it with the Car instance prototype so you have your instance actions
// let's get the car we created previously.
// remember, this is done asynchronously, so we will do our work in a success handler that we provide to get
Car.get({id: 24}, function(myCar) {
// let's update the car now that we have it. let's set the year of the model and the color
myCar.year = 2004;
myCar.color = 'white';
// now, let's save our changes by calling the instance action $save
myCar.$save();
});
// now, let's query for all cars and get an array back
// query is a class function that expects an array of your resource to be returned
Car.query(function(cars) {
// trivial example, we're just going to enumerate the cars we found and log some info about them
for(var i = 0; i < cars.length; i++)
console.log('Found ' + cars[0].color + ' ' cars[0].year + ' ' + cars[0].make + ' ' + cars[0].model);
});
// ok, let's delete the car we created earlier. use the class action delete
Car.delete({id: 24});
}
You can technically call any actions either as a class or as an instance, but it will become obvious that some are awkward to use as instance actions and vise versa. For example, while you technically can use query as an instance action, you wouldn't do that in practice because it's extra work and it's awkward (you'd have to do new Car().$query(). That's silly. Car.query() is easier and makes more sense). So, the usage in my example above represents your normal usage.
Update:
save vs $save
$save is similar to save, but it assumes the data you want to submit during save is itself, since $save is an instance action. It is particularly useful because after the response is received, it'll update itself with the object returned by your HTTP endpoint. So if your service saves the object with some additional values populated on the server side, such as an ID, then sends the object back as JSON, $save will update the instance with the returned JSON object.
var car = new Car({make: 'Toyota', model: 'Prius'});
// at this point there is no id property, only make and model
car.$save(function() {
// angular is async, so we need a success handler to continue the explanation
// assuming your server assigned an ID and sent the resulting object back as JSON, you can now access id off the original object
console.log(car.id); // has a value now
});
You could do something similar with the class method, but it's awkward, particularly if other code in your controller needs to reference the car as you are working on it
Car.save({make: 'Toyota', model: 'Prius'}, function(car) {
// ok, we have an ID now
console.log(car.id);
});
or
var car = new Car({...});
Car.save(car, function(newCar) {
car = newCar; // wut? that's awkward
});
save could be useful during instances where you are quickly saving a small object, or are performing a sort of "fire and forget". Anyways, I rarely use save myself.
Gurus,
Here is my scenario:
I am defining a new client-side property (i.e. fullName) on one my entities using breeze's registerEntityTypeCtor function. The fullName property is coded to check the values of the firstName and lastName properties on the entity to determine it's value. It works when I am doing a query and receiving entities back from the db.
However, when I create a new entity on the client side (calling breeze's createEntity function) or make changes to the firstName or LastName properties without doing a save, then the custom fullName property is never updated until I perform another db pull. With breeze change tracking shouldn't the fullName property update any time either of the name properties changes?
During debug, I noticed that when I use a getter in code: (i.e. var fullName = entity.fullName) -- as I step through the code the ctor is hits the "backingStore" value of my entity which is either default value (using the createEntity) or the last db value, but never the current value of the entity.
What am I missing? Thanks
Here is an example I used for setting up the property:
function registerSpmoleSurvey(metadataStore) {
metadataStore.registerEntityTypeCtor('SpmoleSurvey', spmoleSurvey);
function spmoleSurvey() { }
Object.defineProperty(spmoleSurvey.prototype, 'fullName', {
get: function () {
var ln = this.lastName;
var fn = this.firstName;
return ln ? fn + ' ' + ln : fn;
}
});
}
Look at this page for examples of adding computeds to your Breeze entities -
http://www.breezejs.com/documentation/extending-entities
Pass in an anonymous function as the third parameter that extends the entity.
HI figure out what I was doing wrong...seems that I was a victim of camelCasing and I capitalize the property name inappropriately. Wrong as advertise now :}
Today I've got a problem when I tried using following code to alter the model attribute in the controller
function userlist($trigger = 1)
{
if($trigger == 1)
{
$this->User->useTable = 'betausers'; //'betausers' is completely the same structure as table 'users'
}
$users = $this->User->find('all');
debug($users);
}
And the model file is
class User extends AppModel
{
var $name = "User";
//var $useTable = 'betausers';
function beforeFind() //only for debug
{
debug($this->useTable);
}
}
The debug message in the model showed the userTable attribute had been changed to betausers.And It was supposed to show all records in table betausers.However,I still got the data in the users,which quite confused me.And I hope someone can show me some directions to solve this problem.
Regards
Model::useTable is only consulted during model instantiation (see the API documentation for Model::__construct). If you want to change the model's table on the fly, you should use Model::setSource:
if ( $trigger == 1 ) {
$this->User->setSource('betausers');
}
The table to use is "fixed" when the model is loaded/instantiated. At that time a DB connection object is created, the table schema is being checked and a lot of other things happen. You can change that variable later all you want, Cake is not looking at it anymore after that point.
One model should be associated with one table, and that association shouldn't change during runtime. You'll need to make another model BetaUser and dynamically change the model you're using. Or rethink your database schema, a simple flag to distinguish beta users from regular users within the users table may be better than a whole new table.