How can i pass the different types of errors from Data access layer to presentation layer?
suppose if we take the northwind database
scenario
I want to delete the customer, so i selected one customer in ui and clicked the "delete" button.It internally calls the "delete" in data access layer.
The prerequisite for deleting the customer is that the customer doesn't have any orders.So in data access layer we wil check whether that customer has any orders.If the customer has orders how can we pass the message from dal to presentation layer that the customer has orders and we don't delete.
Am i doing right?is there any other ways to deal with this type?
Thanks in advance
The other answers tell you how you should be implementing this particular scenario, however to answer your original question, the answer is to define your own exceptions.
You can have a core DataLayerException as the base for all of you data exceptions (inheriting from ApplicationException or similar) then have sub exceptions based on the scenario, e.g.:
ConnectionClosedException
TImeoutException
etc.
For me personally, it would be better to call a separate "ValidateDeletion" method prior to attempting a delete. This would first check to see if that customer has orders before removing them from the database.
Particulary, if you want to raise different kinds of exception from database... I use to raise an error from SP like this.
if (#invalidCount <> 1)
Begin
Raiserror('[Duplicate] Record Already Posted In System ', 20, 1)
End
Catch the error in the DAL, and analyse the exception type through the exception message (here the keyword for me is the "[Duplicate]") and throw the different kind of exception appropriately.
Of course this will be very cumboresum if you have more than 2/3 types of exceptions.
For me the best way is to raise an event TryToDeleteCustomerWithOrders.
The validation part is also fine, but it's about data, so the data layer should do the whole work. If you put the validation outside, there is chance that you call the deletion function without validation ....
Related
Is it possible to get multiple error messages for missing required fields in a single error message to the user? For example, if I left all 5 of my required fields blank, the error message that is displayed when clicking Submit will show all 5 messages in the same window.
This is a fantastic idea and should be added to the PeopleSoft Idea Spaces in MyOracle Support. Unfortunately, this is not delivered. There are multiple ways a person might trigger an exception, including:
Choosing an invalid value
Leaving required fields blank
Failing FieldEdit or SaveEdit PeopleCode
Unfortunately, PeopleSoft fails on the first, not all. Regarding the last item: FieldEdit/SaveEdit, as soon as you trigger the PeopleCode Error function, PeopleCode halts, so it is impossible for us to use the Error function to queue multiple exceptions.
With all that said, nothing is impossible. One way to accomplish this would be to use our own JavaScript/CSS to mark all fields that fail validation. This would require us to write additional PeopleCode, etc., to work around Oracle's delivered validation.
One approach to do that is to perform the validations "manually", stack then and present to the user.
In order to do that, you need to have a custom "Save" or "Validate Button", and your peoplecode would stack the errors.
You can use the vanilla required fields validation + any conditional validation you need.
A good way to present this is just have a field(long) or an html area and nicely present the errors:
Emplid is required
Setid is required
Enter an end date less than start date
But otherwise, this is not part of Peopletools, although some modules do offer this (eSupplier Portal for instance has a similar feature).
Currently in the ASP.NET application I'm developing, basic validations (ie required fields) are being done in the Presentation Layer, using Validators and a ValidationSummary. This is working great for me specifically since the ValidationSummary will display multiple error messages (assuming multiple Validators are set to invalid).
I also have some validations being done in the business layer - due to their complexity (and data service layer reliance) I'd rather not keep them in the presentation layer. However, I'm not sure the best way to send these back to the presentation layer for display to the user. My initial consideration is to send back a List<string> with failed validation messages and then dynamically create a CustomValidator control (since apparently you can only bind one error message to one Validator control) for each error to show in the ValidationSummary when there are any.
I'm assuming I'm not the first one to come across this issue, so I'm wondering if anyone has any suggestions on this.
Thanks!
There are essentially two ways to do this: either by passing back an error code/object from your business layer, or throw out an exception. You can also combine both.
For an example, you can take a look SqlException class. When you send a SQL to SQL Server, it runs a query parser to parse your SQL first. If it sees syntax error, then it will throw out a SqlException and terminate the query. There may be multiple syntax errors in your query. So SqlExeption class has an Errors property that contains a list of errors. You can then enumerate through that list in your presentation layer to format your error message, probably with a CustomValidator.
You can also simply just return the error list without throwing an exception. For example, you can have your function to return a List in case at least one error occurred and return null in case the call was successful. Or you can pass List as an argument into your function. They are all fine, it all depends on which way you feel is more convenient. The advantage of throwing out an exception is it unwinds multiple call frames immediately, so you don’t have to check return value on every level. For example, if function A calls function B , B calls function C, C sees something wrong, then if let C to return an error object (or error code), then B has to have code to check whether C returned an error and pass that error code/value back, A have to check it as well ---- you need to check it on every level. On the other hand, if you just let C to throw an exception, then the code goes straight to the exception handler. You don’t have check return values on every level.
I will try to be as concise as possible. I'm using Flex/Hibernate technologies for my app. I also use Cairngorm micro-architecture for Flex. Because i'm beginner, i have probably misunderstand something about Caringorm's ModelLocator purpose. I have following problem...
Suppose that we have next data model:
USER ----------------> TOPIC -------------> COMMENT
1 M 1 M
User can start many topics, topics can have many comments etc. It is pretty simple model, just for example. In hibernate, i use EAGER fetching strategy for unidirectional USER->TOPIC and TOPIC->COMMENT relations(here is no question about best practices etc, this is just example of problem).
My ModelLocator looks like this:
...
public class ModelLocator ....
{
//private instance, private constructor, getInstance() etc...
...
//app state
public var users:ArrayCollection;
public var selectedUser:UserVO;
public var selectedTopic:TopicVO;
}
Because i use eager fetching, i can 'walk' through all object graph on my Flex client without hitting the database. This is ok as long as i don't need to insert, update, or delete some of the domain instances. But when that comes, problems with synchronization arise.
For example, if i want to show details about some user from some UserListView, when user(actor) select that user in list, i will take selected index in UserList, get element from users ArrayCollection in ModelLocator at selected index and show details about selected user.
When i want to insert new User, ok, I will save that user in database and in IResponder result method i will add that user in ModelLocator.users ArrayCollection.
But, when i want to add new topic for some user, if i still want to use convenience of EAGER fetching, i need to reload user list again... And to add topic to selected user... And if user is in some other location(indirectly), i need to insert topic there also.
Update is even worst. In that case i need to write even some logic...
My question: is this good way of using ModelLocator in Cairngorm? It seems to me that, because of mentioned, EAGER fetching is somehow pointless. In case of using EAGER fetching, synchronization on Flex client can become big problem. Should I always hit database in order to manipulate with my domain model?
EDIT:
It seems that i didn't make myself clear enough. Excuse me for that.
Ok, i use Spring in technology stack also and DTO(DVO) pattern with flex/spring (de)serializer, but i just wanted to stay out of that because i'm trying to point out how do you stay synchronized with database state in your flex app. I don't even mention multi-user scenario and poling/pushing topic which is, maybe, my solution because i use standard request-response mechanism. I didn't provide some concrete code, because this seems conceptual problem for me, and i use standard Cairngorm terms in order to explain pseudo-names which i use for class names, var names etc.
I'll try to 'simplify' again: you have flex client for administration of above mentioned domain(CRUD for each of domain classes), you have ListOfUsersView(shows list of users with basic infos about them), UserDetailsView(shows user details and list of user topics with delete option for each of topic), InsertNewUserTopicView(form to insert new topic) etc.
Each of view which displays some infos is synchronized with ModelLocator state variables, for example:
ListOfUsersView ------binded to------> users:ArrayCollection in ModelLocator
UserDetailsView ------binded to------> selectedUser:UserVO in ModelLocator
etc.
View state transition look like this:
ListOfUsersView----detailsClick---->UserDetailsView---insertTopic--->InsertTopicView
So when i click on "Details" button in ListOfUsersView, in my logic, i get index of selected row in ListOfUsers, after that i take UserVO object from users:ArrayCollection in ModelLocator at mentioned index, after that i set that UserVO object as selectedUser:UserVO in ModelLocator and after that i change view state to UserDetailsView(it shows user details and selectedUser.topics) which is synchronized with selectedUser:UserVO in ModelLocator.
Now, i click "Insert new topic" button on UserDetailsView which results in InsertTopicView form. I enter some data, click "Save topic"(after successful save, UserDetailsView is shown again) and problem arise.
Because of my EAGER-ly fetched objects, i didn't hit the database in mentioned transitions and because of that there are two places for which i need to be concerned when insert new topic for selected user: one is instance of selectedUser object in users:ArrayCollection (because my logic select users from that collection and shows them in UserDetailsView), and second is selectedUser:UserVO(in order to sync UserDetailsView which comes after successfull save operation).
So, again my question arises... Should i hit database in every transition, should i reload users:ArrayCollection and selectedUser:UserVO after save in order to synchronize database state with flex client, should i take saved topic and on client side, without hitting the database, programmatically pass all places which i need to update or...?
It seems to me that EAGER-ly fetched object with their associations is not good idea. Am i wrong?
Or, to 'simplify' :) again, what should you do in the mentioned scenario? So, you need to handle click on "Save topic" button, and now what...?
Again, i really try to explain this as plastic as possible because i'm confused with this. So, please forgive me for my long post.
From my point of view the point isn't in fetching mode itself but in client/server interaction. From my previous experience with it I've finally found some disadvantages of using pure domain objects (especially with eager fetching) for client/server interaction:
You have to pass all the child collections maybe without necessity to use them on a client side. In your case it is very likely you'll display topics and comments not for all users you get from server. The most like situation you need to display user list then display topics for one of the selected users and then comments for one of the selected topics. But in current implementation you receive all the topics and comments even if they are not needed to display. It is very possible you'll receive all your DB in a single query.
Another problem is it can be very insecure to get all the user data (or some other data) with all fields (emails, addresses, passwords, credit card numbers etc).
I think there can be other reasons not to use pure domain objects especially with eager fetching.
I suggest you to introduce some Mapper (or Assembler) layer to convert your domain objects to Data Transfer Objects aka DTO. So every query to your service layer will receive data from your DAO or Active Record and then convert it to corresponding DTO using corresponding Mapper. So you can get user list without private data and query some additional user details with a separate query.
On a client side you can use these DTOs directly or convert them into client domain objects. You can do it in your Cairngorm responders.
This way you can avoid a lot of your client side problems which you described.
For a Mapper layer you can use Dozer library or create your own lightweight mappers.
Hope this helps!
EDIT
What about your details I'd prefer to get user list with necessary displayable fields like first name and last name (to display in list). Say a list of SimpleUserRepresentationDTO.
Then if user requests user details for editing you request UserDetailsDTO for that user and fill tour selectedUser fields in model with it. The same is for topics.
The only problem is displaying list of users after user details editing. You can:
Request the whole list again. The advantage is you can display changes performed by other users. But if the list is too long it can be very ineffective to query all the users each time even if they are SimpleUserRepresentationDTO with minimal data.
When you get success from server on user details saving you can find corresponding user in model's user list and replace changed details there.
Tell you the truth, there's no good way of using Cairngorm. It's a crap framework.
I'm not too sure exactly what you mean by eager fetching (or what exactly is your problem), but whatever it is, it's still a request/response kind of deal and this shouldn't be a problem per say unless you're not doing something right; in which case I can't see your code.
As for frameworks, I recommend you look at RobotLegs or Parsley.
Look at the "dpHibernate" project. It implements "lazy loading" on the Flex client.
We have a WebForms Control which requires that the ID of another Control implementing ITextControl is provided.
What exception should we throw if there is no control with that ID or a control is found but it's not implementing the interface?
var text = Page.FindControl(TextProviderId) as ITextControl;
if (text == null) {
throw new WhatEverException(...);
...
Should we split it into two cases and throw one exception if there is no control with that ID, and another one if said control does not implement ITextControl? If so, which exceptions should we use then?
If the control should really be there, I would say that your web form is in an invalid state if it is missing, so I would probably go for InvalidOperationException:
The exception that is thrown when a method call is invalid for the object's current state.
This would be applicable to both scenarios; regardless of whether the control is missing or if it does not implement the expected interface, the containing object is in an invalid state.
If this is a scenario that is expected to happen for various reasons (let's say that you are making some tool that others will program against, and this is a situation that they might very well produce), perhaps you should instead create two custom exceptions that make it very clear what is happening and how to correct it (such as ControlNotFoundException and InterfaceNotFoundException or something similar).
ArgumentOutOfRangeException?
Whether or not you should split them up into different exceptions probably depends most on whether or not you think it is likely that anyone will ever want to distinguish the two exceptions in different catch blocks.
Not knowing exactly how this will be used, this seems like the kind of error that should be brought to the developer's attention, where rewriting code to point to the correct file or implement the correct interface is the proper action, rather than implementing a try-catch and give the user friendly error messages. As such, I'd just throw an ArgumentException.
Just trying to gather thoughts on what works/doesn't work for manipulating Business/Domain objects through an ASP.NET (2.0+) UI/Presentation layer. Specifically in classic ASP.NET LOB application situations where the ASP.NET code talks directly to the business layer. I come across this type of design quite often and wondering what is the ideal solution (i.e. implementing a specific pattern) and what is the best pragmatic solution that won't require a complete rewrite where no "pattern" is implemented.
Here is a sample scenario.
A single ASP.NET page that is the "Edit/New" page for a particular Business/Domain object, let's use "Person" as an example. We want to edit Name and Address information from within this page. As the user is making edits or entering data, there are some situations where the form should postback to refresh itself. For example, when editing their Address, they select a "Country". After which a State/Region dropdown becomes enabled and refreshed with relevant information for the selected country. This is essentially business logic (restricting available selections based on some dependent field) and this logic is handled by the business layer (remember this is just one example, there are lots of business situations where the logic is more complex during the post back - for example insurance industry when selecting certain things dictates what other data is needed/required).
Ideally this logic is stored only in the Business/Domain object (i.e. not having the logic duplicated in the ASP.NET code). To accomplish this, I believe the Business/Domain object would need to be reinitialized and have it's state set based on current UI values on each postback.
For example:
private Person person = null;
protected void Page_Load()
{
person = PersonRepository.Load(Request.QueryString["id"]);
if (Page.IsPostBack)
SetPersonStateFromUI(person);
else
SetUIStateFromPerson(person);
}
protected void CountryDropDownList_OnChange()
{
this.StateRegionDropDownList.Enabled = true;
this.StateRegionDropDownList.Items.Clear();
this.StateRegionDropDownList.DataSource = person.AvailableStateRegions;
this.StateRegionDropDownList.DataBind();
}
Other options I have seen are storing the Business object in SessionState rather than loading it from the repository (aka database) each time the page loads back up.
Thoughts?
I'd put your example in my 'UI Enhancement' bucket rather than BL, verifying that the entries are correct is BL but easing data entry is UI in my opinion.
For very simple things I wouldn't bother with a regular post back but would use an ajax approach. For example if I need to get a list of Cities, I might have a Page Method (Or web service) that given a state gives me a list of cities.
If your options depends on a wide variety of parameters, what your doing would work well. As for storing things in Session there are benefits. Are your entities visible to multiple at the same time? If so what happens when User A and User B both edit the same. Also if your loading each time are you savign to the database each time? What happens if I am editing my name, and then select country, but now my browser crashes. Did you update the name in the DB?
This is the line I disagree with slightly:
this.StateRegionDropDownList.DataSource = person.AvailableStateRegions;
Person is a business/domain object, but it's not the object that should be handling state/region mapping (for example), even if that's where the information to make the decision lives.
In more complicated examples where multiple variables are needed to make a decision, what you want to do in general is start from the domain object you're trying to end up with, and call a function on that object that can be given all the required information to make a business decision.
So maybe (using a static function on the State class):
this.StateRegionDropDownList.DataSource = State.GetAvailableStateRegions(person, ipAddress);
As a consequence of separating out UI helper concerns from the Person domain object, this style of programming tends to be much "more testable".