I have a sling-model that needs to do some costly operations at initialization. These are related to the page scope, meaning based on currentPage properties. Hence it would make sense that the model gets initialized only once per page call.
I found a nice article regarding this at how to call sling model only once where they are setting the cache property of the Model-annotation to true.
But this unfortunately only works per resource.
So setting the cache=true property the model gets initialized for every component that calls it via data-sly-use. It only helps wenn calling data-sly-use in the same component (resource), but that's not helpful.
Can I somehow have the model cached for the entire lifecycle of the page-request?
SlingHttpServletRequest is a wrapper around HttpServletRequest and supports setAttribute and getAttribute methods provided by servlet api.
Setting attributes:
slingRequest.setAttribute(ATTRIBUTE_NAME, myobject);
Retrieve:
//check for null
MyClass myobject = (MyClass) slingRequest.getAttribute(ATTRIBUTE_NAME);
Related
I have been pondering the internals of and relationship between context, contextbinding, and bindingcontext for a few days now and i am not sure whether there is a major misconception on my side. Maybe some of you can help me sort it out. I am putting my assumptions below. I might want to say first that I always work with oData models here.
This is what I believe to understand reading the documentation:
A context is a reference to a data object in a model.
A binding is basically an event provider which (in case of a one way binding) observes the status of a specific context and emits events when it is changed/data loaded ... and therefore allows for registering event handlers for events on that specific context. In terms of programming objects, there are property bindings and list bindings (is this true - or is list binding all that is ever relevant?).
At any rate, my understanding is that a list binding is the model-side of a component's aggregation binding, while a property binding is called property binding both from a component's and a model's point of view (confusing?).
Now what I do not quite get is:
The context binding new sap.ui.model.ContextBinding(oModel, sPath, oContext, mParameters?, oEvents?): takes a path and a context as a parameter. I am assuming that this oContext is not exactly the context described above but some metadata on the binding. is this correct? Or is this the definition of thep ath which the path parameter is relative to?
What also seems weird is when you want to create a context itself new sap.ui.model.Contextabov(oModel, sPath, oContext) takes a context again.
I believe that this is just an unfortunate naming thing i am looking at, but I am not quite sure.
Then there is contextbinding and bindingcontext. I'd assume that contextBinding is the binding to a specific context as described e. And a bindingcontext is the meta data regarding a context- or list binding.
From a programming point of view, I do not understand why the following works:
create list binding to context via model.bindList() passing a path only.
attach change-event handler to binding
call get_contexts() on binding
receive data in change event handler (and see the oData-property filled in the model).
and there seems to be no way of doing the same for a property binding which i'd assume I can generate via model.bindProperty(). I can generate the binding, but the binding I receive seems to have no handle to actually fetch data.
I hope the ramble explains my problem. In case you ask : what do you want to do? I actually do not want to do anything with it, I just do not quite understand how this works. Binding to ui controls and so forth works just fine, but I'd prefer to really understand what is underneath the hood. I have been reading debug files and unit tests a bit, but discussing it with you guys seems a great way as well.
If this is unclear I'll happily add anything that helps.
Cheers
Michel
your questions are answered below. Hope it helps.
Now what I do not quite get is: The context binding new sap.ui.model.ContextBinding(oModel, sPath, oContext, mParameters?, oEvents?): takes a path and a context as a parameter. I am assuming that this oContext is not exactly the context described above but some metadata on the binding. is this correct? Or is this the definition of thep ath which the path parameter is relative to?
the oContext is the context you mentioned above, to be precise, is sap.ui.model.Context.
What also seems weird is when you want to create a context itself new sap.ui.model.Context(oModel, sPath, oContext) takes a context again. I believe that this is just an unfortunate naming thing i am looking at, but I am not quite sure.
I guess the documentation here confused you. Actually, sap.ui.model.Context only takes oModel and sPath as parameters. The following code is what i get from sap-ui-core.js. You can see the JSDoc part about parameters is actually inconsistent with the code. Maybe there is some kind of typo there.
/**
* Constructor for Context class.
*
* #class
* The Context is a pointer to an object in the model data, which is used to
* allow definition of relative bindings, which are resolved relative to the
* defined object.
* Context elements are created either by the ListBinding for each list entry
* or by using createBindingContext.
*
* #param {sap.ui.model.Model} oModel the model
* #param {String} sPath the path
* #param {Object} oContext the context object
* #abstract
* #public
* #name sap.ui.model.Context
*/
var Context = sap.ui.base.Object.extend("sap.ui.model.Context",
/** #lends sap.ui.model.Context.prototype */ {
constructor : function(oModel, sPath){
sap.ui.base.Object.apply(this);
this.oModel = oModel;
this.sPath = sPath;
},
metadata : {
"abstract" : true,
publicMethods : [
"getModel", "getPath", "getProperty", "getObject"
]
}
});
From a programming point of view, I do not understand why the following works:
create list binding to context via model.bindList() passing a path only.
attach change-event handler to binding
call get_contexts() on binding
receive data in change event handler (and see the oData-property filled in the model).
and there seems to be no way of doing the same for a property binding which i'd assume I can generate via model.bindProperty(). I can generate the binding, but the binding I receive seems to have no handle to actually fetch data.
Actually you can also attachChange event to sap.ui.model.PropertyBinding, and you can call getValue() to get the data.
Thanks, Allen, that really helped. It really mainly was a confusion regarding the documentation and the getValue slipped me as well.
To add another answer to a question only implicitly included in the title:
context binding: the binding you set up to a given path.
binding context: the context of a given binding, i.e. when coming from a component, or some other set up binding.
Cheers
Michel
Briefly, I'm loading objects that descend from a base class using a repository defined against the base class. Although my objects are created with the correct descendant classes, any descendant classes that add navigation properties not present in the base class do not have those related objects loaded, and I have no way to explicitly request them.
Here is a simple method in a repository class that loads a given calendar event assuming you know its ID value:
public CalendarEvent GetEvent(int eventId)
{
using (var context = new CalendarEventDbContext(ConnectionString))
{
var result = (from evt in context.CalendarEvents
where eventId.Equals((int)evt.EventId)
select evt).ToList();
return result.ToList()[0];
}
}
CalendarEvent is a base class from which a large number of more specific classes descend. Entity Framework correctly determines the actual class of the calendar event specified by eventId and constructs and returns that derived class. This works perfectly.
Now, however, I have a descendant of CalendarEvent called ReportIssued. This object has a reference to another object called ReportRequest (another descendant of CalendarEvent, although I don't think that's important).
My problem is that when Entity Framework creates an instance of ReportIssued on my behalf I always want it to create and load the related instance of ReportRequested, but because I am creating the event in the context of generic calendar events, although I correctly get back a ReportIssued event, I cannot specify the .Include() to get the related object. I want to do it through this generically-expressed search because I won't necessarily know the type of eventId's event and also I have several other "Get" methods that return collections of CalendarEvent descendants.
I create my mappings using the Fluent API. I guess what I'm looking for is some way to express, in the mapping, that the related object is always wanted or, failing that, some kind of decorator that expresses the same concept.
I find it odd that when saving objects Entity Framework always walks the entire graph whereas it does not do the equivalent when loading objects.
In one of my extbase models, I want to initialize some properties derived from the properties that are saved in the database. The computation of these virtual properties is time consuming, so I'd like to cache them. Thus my program flow should look somehow like this:
Load the domain object as usual from the database
Check if the virtual property is available in cache. If so, fetch it from there, otherwise compute and cache it.
I first thought the method "initializeObject" is what I need, but it is not: It is called before any property is initialized from the database. So I came up with two other ways:
I can call an initialization-method manually from the repository after fetching the object, but that seems weird and would break if someone adds another find* method to the general repository.
Another idea is to add a boolean "virtualPropertiesInitialized" to the model, query it whenever one of the virtual properties is accessed and initialize the virtual properties if needed. Also seems weird, but would not break if someone adds another "find"-method to the generic repository.
My question is:
Is there a default/best-practice how to do what I want to do?
If reading the final value from disk or database is less computationally intensive, then store the value using the TYPO3 caching framework or by your own caching method of a static class and restore it in the getter of the virtual property. Doing it in the getter method public mixed getYourPropery() will give you the feature that the value is only get from the cache when you call it.
On the second call, just return the value you stored previously:
private $myValue = NULL;
public function getMyValue() {
if($this->myValue != NULL) return $this->myValue;
$this->myValue = "test";
return $this->myValue;
}
Does anyone have or know of an example which demonstrates loading data via a GWT RPC call into a ListStore using Sencha GXT 3.0? I know there are numerous examples of using the ModelData and BeanModel interfaces used in the 2.x versions but 3.0 does away with the need to use these interfaces and supposedly allows for POJO objects to be loaded in using classes which implement the ValueProperty interface.
I have seen the RequestFactoryBinding example and the RequestFactory Grid example in the 3.0 Explorer but those appear to demonstrate the use of a custom Data Proxy and a Receiver. I assume from reviewing the code in those examples that these techniques/classes may be required but that is not made apparent anywhere. It's possible that there is more documentation forthcoming but so far I haven't been able to find much of anything beyond that javadocs and the Explorer which lacks some of the source classes used in the example methods.
Links to both examples below.
The RequestFactoryBinding Example:
http://www.sencha.com/examples/#ExamplePlace:requestfactorybinding
RequestFactory Grid example:
http://www.sencha.com/examples/#ExamplePlace:requestfactorygrid
DataProxy and Loader are used mostly to facilitate a) relying on the server for filtering/paging/sorting, or b) reuse between parts of the application for getting access to the same pieces of data. They are not required (as in 2.x) in cases where the client only loads data once, or where manual store management is done.
The various store loading classes (ListStoreBinding, LoadResultListStoreBinding) demonstrate internally how the ListStore can be fed items. This first way allows you to replace the existing items in the store from the onSuccess method in your RPC callback or RequestFactory receiver:
List<MyData> newItems = ...;//response from server
ListStore<MyData> store = ...;//current store to replace/update
store.replaceAll(newItems);
If only loading once, or only appending, not replacing, the other method should be used:
store.addAll(newItems);
Items can be added one by one using store.add, however this will result in an event per item, and should be avoided.
Edit: Also, and this may not totally be clear coming from 2.x, but no superclass/interface is required for data itself. ValueProvider is only used as an external abstraction for how models are manipulated - how values are generically read or set from any kind of model. The PropertyAccess interface allows ValueProvider (and other) instances to be generated by just the property name that the values will be get/set from using bean accessors. ValueProvider types/instances are not required for loading data, merely for the data widgets themselves to extract the data they are displaying, and to make modifications after the user edits the values.
Knowing these pieces, the loader/proxy mechanism will be loading data in the same basic way. The Loader is responsible for being told what settings (paging, filtering, and/or sorting) to use when loading, then triggering the load - different subclasses have different responsibilities, accept different load config types, and return different results. The DataProxy then is the mechanism that actually talks to whatever holds the data, asynchronously if on a server, and informs the loader when the results are available via a callback.
The examples listed in the question both use RequestFactory, but there are several examples as well that use RPC, and a few loading from just JSON or XML. In http://www.sencha.com/examples/#ExamplePlace:paginggrid the main data loading parts are as follows:
// The rpc async instance
final ExampleServiceAsync service = GWT.create(ExampleService.class);
// As in Ext GWT 2, there is a convenience proxy for RPC to just pass the callback
// directly to the RPC call. If you need a custom callback, just be sure to invoke
// `callback.onSuccess` with the final result.
RpcProxy<PagingLoadConfig, PagingLoadResult<Post>> proxy = new RpcProxy<PagingLoadConfig, PagingLoadResult<Post>>() {
#Override
public void load(PagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Post>> callback) {
service.getPosts(loadConfig, callback);
}
};
// ...
// The loader itself has a reference to the proxy so that loader.load() results
// in a round trip to the server, as outlined above.
final PagingLoader<PagingLoadConfig, PagingLoadResult<Post>> loader = new PagingLoader<PagingLoadConfig, PagingLoadResult<Post>>(
proxy);
loader.setRemoteSort(true);
// This last piece - instead of 2.x where the loader is a parameter to the store,
// in 3 you directly wire the results of the loader to add the items into the
// store, as discussed in the first half of this answer
loader.addLoadHandler(new LoadResultListStoreBinding<PagingLoadConfig, Post, PagingLoadResult<Post>>(store));
FWIW I spiked a GWTP Dispatch version of a remotely paged and sorted grid. Which is GWT RPC with a command pattern twist.
Assuming you're familiar with grids, you'll require an instance of:
RpcProxy
PagingLoader
LoadResultListStoreBinding
And the methods that need to be invoked:
PagingLoader.setRemoteSort(true)
PagingLoader.addLoadHandler()
Grid.setLoader()
PagingToolBar.bind()
I am building an ASP.NET 4.0 MVC 2 app with a generic repository based on this blog post.
I'm not sure how to deal with the lifetime of ObjectContext -- here is a typical method from my repository class:
public T GetSingle<T>(Func<T, bool> predicate) where T : class
{
using (MyDbEntities dbEntities = new MyDbEntities())
{
return dbEntities.CreateObjectSet<T>().Single(predicate);
}
}
MyDbEntities is the ObjectContext generated by Entity Framework 4.
Is it ok to call .CreateObjectSet() and create/dispose MyDbEntities per every HTTP request? If not, how can I preserve this object?
If another method returns an IEnumerable<MyObject> using similar code, will this cause undefined behavior if I try to perform CRUD operations outside the scope of that method?
Yes, it is ok to create a new object context on each request (and in turn a call to CreateObjectSet). In fact, it's preferred. And like any object that implements IDisposable, you should be a good citizen and dispose it (which you're code above is doing). Some people use IoC to control the lifetime of their object context scoped to the http request but either way, it's short lived.
For the second part of your question, I think you're asking if another method performs a CRUD operation with a different instance of the data context (let me know if I'm misinterpreting). If that's the case, you'll need to attach it to the new data context that will perform the actual database update. This is a fine thing to do. Also, acceptable would be the use the Unit of Work pattern as well.