I am working on improving the performance of DataAccess Layer of an existing Asp.Net Web Application. The scenerios are.
Please can I get some suggestions here?
EDIT 1: I have tried using Lazy loading but the issue is that since the Entity is also used as DataContract it triggers the lazy loading during Serialization. Using a DTO Objects is an option but that is a huge change as no of Entities are huge. Without the Test cases this will require a huge amount of manual Testing effort.
EDIT 2: The project was written long back with no flexibility to write unit tests. E.g The entity itself contains the CRUD operation and uses NHibernate Session.
class SampleEntity : ICrudOperation
{
//fields and properties
public IList<SampleEntity> Update()
{
//perform business logic (which can be huge and call the ICrudOperation of
//other entities
ISession session = GetSessionFromSomewhere();
session.Update(this);
}
}
This is just an example for Update. And there are around 400 Entities which are interdependent. Is there a way to write unit test for this
It does seem that the architecture here could be improved.
The main problem seems to be that huge amounts of data are being read. Does all of this data need to be read? For example If entity A has a list of child elements B that are being loaded eagerly, but only fields from entity A are displayed on the page then only entity A needs to be read. If everything is displayed on the page consider re-designing the page so that you have to navigate to a different page to see entity B data.
Assuming that you are only displaying data from entity A or that the web site can be re-designed to do this then the first thing will be to turn on lazy loading of the child entities so that you will only need to read them if you really need the data. Secondly, if you continue to return the entities themselves turning on lazy loading will have no effect as when the serializer serializes your data, the child entities will still be read. You will need to introduce some data transfer objects (DTOs) to pass the data over the wire. These will be similar to your entities but will only have fields for the data you actually want to use on your web page. You will then need to translate your entities to the DTOs which means because you won't access lists of children entities that you don't need, with lazy loading configured, that data won't get read.
It is worth investigating upgrading to the latest version of NHibernate although with no unit tests this will probably be scary but definitely worth it.
Introducing second level cache will probably have very little effect as this really starts to make a difference when you are getting lots of hits in a distributed environment. You have more fundamental problems to resolve first.
This combination will reduce the number of initial SQL joins, and reduce the size of your object graph.
However, this will lead to the next problem:
Your consumers/clients will not have access to all of the data. They will need to make multiple calls to the server to retrieve child objects/collections.
You could try to anticipate which child objects/collections will be needed (and eager load them), but it could be a cumbersome exercise. A simpler option would be to check for null objects/collections (i.e at the consumer), and make the call to the server to fetch additional data.
Are your SQL JOINs slow? You might try replacing fetch=join with fetch=select, and see if that speeds things up.
Determine the time being spent in SQL, vs the time taken to send data over the wire. You might consider compressing your object graph before your send it over the wire.
Swap any Nhibernate lazy proxies with your own custom lazy-load proxies, before returning the object graph to the consumer. Your custom proxies will lazy load data over WCF/Web Services (instead of calling the db). I've had some success using this technique on a rich client.
In theory, this should allow your client code to remain as-is. There's a thread here along those lines.
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With