It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
It is probably a kind of architectural question, but still it has to have a 'best practice solution' or an accepted standard.
I am talking about some kind of static data that needs to be displayed on site, like catalogue of products, list of menus and menu items, list of breadcrumb blocks etc. This option is available when using any standard CMS, I suppose.
But I would like to use a pure JSF solution for this issue.
So, to get back to the question, my elaborations stem upon the following principles:
Data shouldn't be hardcoded in facelets, hence I use database to hold the values, like in the following db script (MYSQL in my case):
CREATE TABLE CatalogueGroup (
CatalogueGroupName VARCHAR(100) NOT NULL PRIMARY KEY,
URLPath VARCHAR(200) NOT NULL,
ParentGroupName VARCHAR(100) DEFAULT NULL,
FOREIGN KEY (ParentGroupName) REFERENCES CatalogueGroup(CatalogueGroupName) ON UPDATE CASCADE ON DELETE SET NULL
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
I would then like to use the entity class to be held in a #ManagedBean and display it in a view, like
public class CatalogueGroup implements Serializable {
private String catalogueGroupName;
private List<CatalogueGroup> children = new ArrayList<CatalogueGroup>();
private CatalogueGroup parentGroup;
//other stuff of this bean
}
#ManagedBean
#SessionScoped
public class CatalogueBean implements Serializable {
private CatalogueGroup catalogue;//loaded via CatalogueGroupDAO with condition parentGroup == null
//other stuff of this bean
}
//snippet of xhtml view for a two-level catalogue
<ul><h:outputText value="#{catalogueBean.catalogue.catalogueGroupName}" />
<ui:rereat value="#{catalogueBean.catalogue.children}" var="group">
<li><h:outputText value="#{group.catalogueGroupName}" /></li>
</ui:repeat>
</ul>
The abovementioned setup works, but it feels like it is an awkward one.
So, I would like to raise the following open, 'best practice' questions to the jsf community:
What is a proper way of setting up a catalogue bean like this:
A #SessionScope bean that will be loaded once and redisplayed on every view or
A #RequestScoped bean that will access database on every page display.
Is there a way to setup recursive functions in facelet view, or I should limit the catalogue nesting level to, say, 2 or 3.
I would like to display some kind of modified catalogue, exposing more groups to the logged in users, depending on his role (column added in a database table) and display basic catalogue when no user logs in. Additionally, I would like to occasionally insert some new groups in the catalogue and not force users to re-log in, but redisplay proper data at once:
Shall I filter groups in business layer and expose a filtered CatalogueGroup to the bean, or I will load the whole catalogue and limit its children in views with rendered=false;
Is exposure of a whole catalogue in session a proper way to go;
Is it possible to send modification events on adding new database entries to all current CatalogueBean active on server forcing to refresh their properties (CatalogueGroup) or to achieve this functionality I need to use #RequestScoped bean only;
In case using request scoped bean is the only alternative will it be wise to access database to get data so often that rarely change or there is a smarter way of doing things;
When user logs in (and logs out) there is already an instance of session scoped catalogue, how to refresh it: do I need to manually do it in action/action listener or I need to invalidate session or do something more appropriate to the situation.
Very interesting but maybe so open fielded question.
First of all the scope depends on which utility you will give to your catalog. I suggest you to go through #ViewScoped if you want to link the data to a particular view or #SessionScoped if your aim is to implement something like a shopping basket.
For the recursive functions I think you should avoid that kind of practice in pure view (xhtml) layer and use a library like Primefaces or Richfaces which have built-in component for what you want to do. Using them you only have to take care of their logical structure programatically inside your managed backing bean.
Finally, for catalog limitations, I suggest you to load only what you are going to use from the database. In that way you are not overloading neither the server-database or the server-client connections. You can have a #SessionScoped bean which manages current logged user's session and depending on that you can ask the database for some values or others.
Also you have to take care about your catalog, if you are doing a lot of modifications on it during the session, maybe #ViewScoped bean is a better choice, because it will be realoaded each time view is requested. If you use #SessionScoped bean for that you have to manually add each change on it, in order to maintain it updated during the session.
"load the whole catalogue and limit its children in views with rendered=false"
That's a work you don't have to do if you do it the way I say. Conditionally evaluating each of the tree nodes can be a hell if you are managing a complex tree and introduces more logic into the view. Definitely you should avoid that as far as you can.
Even you have already reached a solution, that's my main idea about that.
You can use a cache to store the menus for various user roles. Then you either invalidate the cache when you insert new data in the database (if you insert this from an administration page) or you can set the cache to expire after a certain period (once a day, every few hours, etc.) and you read again the data when the cache expires.
Related
For a past few days I'm facing a task which became problematic for me.
I'm using rich:dataTable with own filtering and sorting columns. Simple inputs or selects with standard sorting and filtering beans in back end. My problem is that I need to remember somehow this sorting and filtering values for many forms to restore them in some case whens - eg.: user uses a back button (the most important case). I know how to handle browser back button, but I don't know have to save and restore my values in some easy and clear way. The important thing is that I can't use rich:extandedDataTable and I use view scope of beans.
(One of solutions was to use session scope bean to manage s&f, but make one bean for one form is far to expensive and making one such a bean is quite complicated to use in the way i want to use it.)
So, my question is: how can I do it? What is the best practice to deal with such a things? Which path should I go?
I'm using RF 4.3 and Mojarra 2.1.17 (it's not so important I think).
Ideally, the stateVar attribute would be ideal for your needs,but documentation on it is sparse and no one seems to really know what to do with it. I'll recommend the following hack, which basically has you save and restore the state of the datatable variables by hand
If you simply want to preserve the current filter state of the table, RF datatable has a getComponentState() method that does basically that. If you want specific values to store, you'll have to dive into the datatable yourself. Whatever you choose, you'll have to do it sometime in the component's lifecycle
Define a suitable <f:event/> listener in which you will capture the state variables of the datatable. I recommend the preValidate.
<rich:extendedDataTable binding="#{bean.table}" ...>
<f:event type="preValidate" listener="bean.saveTableState"/>
</rich:extendedDataTable>
Then define the method in your backing bean that will retrieve the state variables from the table binding
public void saveTableState(ComponentSystemEvent evt){
UIExtendedDataTable table = (UIExtendedDataTable)evt.getComponent();
//now you have the table, you can get what you need from it
DataComponentState savedState = table.getComponentState(); //this object obtained here you can restore to reset the table to it's condition when you obtained the state.
//or go into the table's hierarchy to retrieve specific values
Iterator<UIComponent> cols = table.columns();
while(cols.hasNext()){
UIColumn col = (UIColumn)cols.next();
col.getFilterValue(); //Retrieve the current filter value on the column
}
}
Depending on your preference, find a suitable point in the component's lifecycle to restore the values. I'll recommend preRenderComponent.
public void restoreTableConditions(ComponentSystemEvent evt){
table.restoreState(FacesContext.getCurrentInstance(),savedState); //restore the DataComponentState from wherever you stashed it
}
Our problem is a very basic, simple implementation of editing the database using JSF + EJB.
Keeping things short:
two separate XHTML views, use two separate Managed Beans #RequestScope.
WebuserListBean and EditWebuserBean, and with #ManagedProperty we inject WebuserListBean, so we could obtain selected user data. So far no problems. Views are filled with data succesfully!
BUT!
We want to be able to edit the user!
And here (to my surprise) we cannot overcome the problem.
1st try:
Because the request scoped bean is dead after filling the view, on Save() method the #PostConstruct tries to launch again, of course it can't. So we couldn't even obtain it from database or anything.
2nd try:
Because the request scoped bean is dead after filling the view, if we do not set up user as field in #postconstruct, we lose our connection with user object which was linked on previous view (and injected, but now that view is dead too).
3rd try:
Cannot inject RequestScope in ViewScoped
Ok and our restrictions, because we think it's wrong way:
We dont want to create a SessionScoped Managed Bean for this
We dont want to use any params etc. We want to use EJB
We are not sure if we could store data in Stateful session bean which is our
endpoint for the module? Is it proper approach?
Thanks for any advice, we could paste some code but i guess it is pointless!
Cheers!
There are many ways to do it, but I recommend using the flash if the pages involved in the navigation are in the same folder (I recently found out reading a BalusC answer that there is a known issue with the flash, in which it will not hold values when navigating between pages in different folders!).
The flash is a way to hold parameters for a little longer than the context of a single request (concept taken from Ruby if I'm not mistaken, someone correct me if I'm wrong), allowing for the sent parameters to be fetched in a subsequent view, for example. Those values are discarded in the second request issued after saving them, if I'm not mistaken. You can inject the flash in your managed beans like this:
#ManagedProperty("#{flash}")
private Flash flash;
public void setFlash(Flash newFlash) {
flash = newFlash;
}
Then, you access it like a map with the put and get methods. If you use the put method in a bean, return a redirection rule and, on the second bean, use the get method your object should be there.
You can also find a highly comprehensible guide of communication in JSF (listing a really extensive list of options) here, in particular if you need to navigate between pages in different folders.
I'm new to the whole ASP world and I'm getting my feet wet by building a C# MVC3/EF4 project. I'm finding it hard to keep from duplicating a bunch of code in my models and view models. Consider an object Foo. I need to do the following things with Foo:
Store records of type Foo in my database.
Allow users to lookup records of an individual Foo (pass instances of Foo to a view).
Allow users to create new instances of Foo (pass instances of Foo to a form).
Let's say I also have a type Bar. A Bar contains a list of Foos. There are two requirements here:
Users can view a list of Bars.
When the user clicks on a specific Bar, it shows all of its Foos.
So, a sketch of my basic objects look like this:
class Foo
{
string FooName;
int Id;
}
class Bar
{
List<Foo> FooList;
int Id;
string Baz;
}
But when I start thinking about the different views, it begins to get messy:
The views shouldn't have any write access to any of the data members.
There's one view that takes a list of Bars but doesn't care about Bar.FooList. Let's say I also want to be good about resource management and close the DbContext as soon as possible (i.e. after the object is in memory but before I render the view). If I just pass it a list of Bars and the designer tries to access the FooList by mistake, we'll get a runtime error. Yuck!
Ok fine, I just create a distinct ViewModel for each view that has read only datamembers, no problem.
But both the database model and the form models will need to have DataAnnotations attached which say which fields are required, max length of the strings, etc. If I create separate form models and database models then I end up having to duplicate all these annotations. Yuck!
So, that's my architectural dilemma: I want to have succinct view models which restrict the views only to reading the data they are supposed to access. I want to avoid repeating data annotations all over the place. And I want to be able to aggressively free my DB resources as soon as possible. What's the best way to achieve my goals?
My advice is do NOT use data annotations in your EF entity classes. Instead, try out the fluent API. It keeps persistence concerns out of the model classes themselves. You can even define the modelbuilder stuff in an entirely different library.
As for having duplicate properties, properties are cheap:
public string MyProp { get; set; }
Not a lot of code, and you may begin to see, the viewmodels and entities need not always be exact duplicates of each other. For example, what if you want to apply [HiddenInput] to a viewmodel, to get it to render as <input type="hidden" />? Would you apply that to the entity? Why? It belongs in the viewmodel (the namespace is even System.Web.Mvc, not System.ComponentModel.DataAnnotations).
As far as duplicating error messages during validation (if you validate the MVC and EF layers separately), you can use resx resources.
As far as freeing db resources, let EF manage that. I find it's best to keep a single DbContext instance per HttpContext. You can open it up using a factory, an OnActionExecuting action filter, Application_BeginRequest, with an IoC container, or whatever. Then dispose context during OnResultExecued, Application_EndRequest, etc. Keeps things simple.
This is something that has been pulling at me for a while. Consider a (MVC type) web application with an ORM (e.g. Nhiberate) as the data access layer.
On one hand - the OOP/Rich domain model hand - I feel I should be passing around (references to) the real objects I am talking about.
On the other hand - the DB/Web App hand - I feel that it is easier and more efficient just to pass the integer Ids of the objects rather than the object themselves.
Consider an ecommerce catalogue type application:
The user is logged in and navigates to a product page.
They post a comment.
The controller action tasked with persisting this comment has 3 pieces of information: a) The user id (from the auth cookie or wherever), b) The product id (probably from the querystring), and c) the comment text.
Now, what what is best practice here? Is it really worth inflating the user and product objects (e.g. by getting them from the repository, with all the DB work that entails) when we know that all they will be used for is so the ORM can read their IDs and set the appropriate foreign keys in the DB table that stores the comments?
What are peoples views on this? Perhaps web apps should be given a little more leway than other apps, due to their stateless nature? I imagine there will be 'it depends' answers, but maybe some people are purists about the issue.
This is a general question which probably is applicable to many platforms, but if giving examples I would prefer them to be ASP.NET MVC if possible.
Thank you.
NHibernate has the load operation (as opposed to doing a get) exactly for this reason.
session.Save(
new Comment
{
Text = commentTextFromScreen,
User = session.Load<User>(userID),
Product = session.Load<Product>(productID)
}
};
In the above example, you are telling NHibernate: I know these already exist in the database, so don't bother selecting them right now. NHibernate will return proxy objects for them and a select won't happen against the database as long as you don't attempt to access any properties on the objects.
For more info check out Ayende's blog post: The difference between Get, Load, and query by id.
When I started using xVal for client-side validation, I was only implementing action methods which used domain model objects as a viewmodel or embedded instances of those objects in the viewmodel.
This approach works fine most of the time, but there are cases when the view needs to display and post back only a subset of the model's properties (for example when the user wants to update his password, but not the rest of his profile data).
One (ugly) workaround is to have a hidden input field on the form for each property that is not otherwise present on the form.
Apparently the best practice here is to create a custom viewmodel which only contains properties relevant to the view and populate the viewmodel via Automapper. It's much cleaner since I am only transferring the data relevant to the view, but it's far from perfect since I have to repeat the same validation attributes that are already present on the domain model object.
Ideally I'd like to specify the Domain Model object as a meta class via a MetaData attribute (this is also often referred to as "buddy class"), but that doesn't work since xVal throws when the metadata class has properties that are not present on the viewmodel.
Is there any elegant workaround to this? I've been considering hacking the xVal sourcecode, but perhaps there is some other way I have overlooked so far.
Thanks,
Adrian
Edit: With the arrival of ASP.NET MVC 2, this is not only a problem related to validation attributes anymore, but it also applies to editor and display attributes.
This is the quintessential reason why your input screens should not be tightly coupled to your model. This question actually pops up here on the MVC tag about 3-4 times a month. I'd dupe if I could find the previous question and some of the comment discussion here is interesting. ;)
The issue your having is you're trying to force two different validation contexts of a model into a single model which fails under a large amount of scenarios. The best example is signing up a new user and then having an admin edit a user field later. You need to validate a password on a user object during registration but you won't show the password field to the admin editing the user details.
The choices for getting around these are all sub-optimal. I've worked on this problem for 3 projects now and implementing the following solutions has never been clean and usually frustrating. I'm going to try and be practical and forget all the DDD/db/model/hotnessofthemonth discussions everybody else is having.
1) Multiple View Models
Having viewmodels that are almost the same violates the DRY principal but I feel the costs of this approach are really low. Usually violating DRY amps up maintenance costs but IMHO the costs for this are the lowest and don't amount to much. Hypothetically speaking you don't change how max number characters the LastName field can have very often.
2) Dynamic Metadata
There are hooks in MVC 2 for providing your own metadata for a model. With this approach you could have whatever your using to provide metadata exclude certain fields based on the current HTTPRequest and therefore Action and Controller. I've used this technique to build a database driven permissions system which goes to the DB and tells the a subclass of the DataAnnotationsMetadataProvider to exclude properties based values stored in the database.
This technique is working great atm but the only problem is validating with UpdateModel(). To solve this problem we created a SmartUpdateModel() method which also goes to the database and automatically generates the exclude string[] array so that any non-permissisable fields aren't validated. We of course cached this for performance reasons so its not bad.
Just want to reiterate that we used [ValidationAttributes] on our models and then superceeded them with new rules on runtime. The end result was that the [Required] User.LastName field wasn't validated if the user didn't have permission to access it.
3) Crazy Interface Dynamic Proxy Thing
The last technique I tried to was to use interfaces for ViewModels. The end result was I had a User object that inherited from interfaces like IAdminEdit and IUserRegistration. IAdminEdit and IUserRegistration would both contain DataAnnotation attributes that performed all the context specific validation like a Password property with the interfaces.
This required some hackery and was more an academic exercise than anything else. The problem with 2 and 3 is that UpdateModel and the DataAnnotationsAttribute provider needed to be customized to be made aware of this technique.
My biggest stumbling block was I didn't ever want to send the whole user object to the view so I ended up using dynamic proxies to create runtime instances of IAdminEdit
Now I understand this is a very xVal specific question but all of the roads to dynamic validation like this lead to customization of the internal MVC Metadata providers. Since all the metadata stuff is new nothing is that clean or simple to do at this point. The work you'd have to do to customize MVC's validation behavior isn't hard but requires some in depth knowledge of how all of the internals work.
We moved our validation attributes to the ViewModel layer. In our case, this provided a cleaner separation of concerns anyway, as we were then able to design our domain model such that it couldn't get into an invalid state in the first place. For example, Date might be required on a BillingTransaction object. So we don't want to make it Nullable. But on our ViewModel, we might need to expose Nullable such that we can catch the situation where the user didn't enter a value.
In other cases, you might have validation that is specific per page/form, and you'll want to validate based on the command the user is trying to perform, rather than set a bunch of stuff and ask the domain model, "are you valid for trying to do XYZ", where in doing "ABC" those values are valid.
If ViewModels are hypothetically being forced upon you, then I recommend that they only enforce domain-agnostic requirements. This includes things like "username is required" and "email is formatted properly".
If you duplicate validation from the domain models in the view models, then you have tightly coupled the domain to the UI. When the domain validation changes ("can only apply 2 coupon per week" becomes "can only apply 1 coupon per week"), the UI must be updated. Generally speaking, this would be awful, and detrimental to agility.
If you move the validation from the domain models to the UI, you've essentially gutted your domain and placed the responsibility of validation on the UI. A second UI would have to duplicate all the validation, and you have coupled two separate UI's together. Now if the customer wants a special interface to administrate the inventory from their iPhone, the iPhone project needs to replicate all the validation that is also found in the website UI.
This would be even more awful than validation duplication described above.
Unless you can predict the future and can rule out these possibilities, only validate domain-agnostic requirements.
I don't know how this will play for client-side validation, but if partial validation is your issue you can modify the DataAnnotationsValidationRunner discussed here to take in an IEnumerable<string> list of property names, as follows:
public static class DataAnnotationsValidationRunner
{
public static IEnumerable<ErrorInfo> GetErrors(object instance, IEnumerable<string> fieldsToValidate)
{
return from prop in TypeDescriptor.GetProperties(instance).Cast<PropertyDescriptor>().Where(p => fieldsToValidate.Contains(p.Name))
from attribute in prop.Attributes.OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty), instance);
}
}
I'm gonna risk the downvotes and state that there is no benefit to ViewModels (in ASP.NET MVC), especially considering the overhead of creating and maintaining them. If the idea is to decouple from the domain, that is indefensible. A UI decoupled from a domain is not a UI for that domain. The UI must depend on the domain, so you're either going to have your Views/Actions coupled to the domain model, or your ViewModel management logic coupled to the domain model. The architecture argument is thus moot.
If the idea is to prevent users from hacking malicious HTTP POSTs that take advantage of ASP.NET MVC's model binding to mutate fields they shouldn't be allowed to change, then A) the domain should enforce this requirement, and B) the actions should provide whitelists of updateable properties to the model binder.
Unless you're domain is exposing something crazy like a live, in-memory object graph instead of entity copies, ViewModels are wasted effort. So to answer your question, keep domain validation in the domain model.