5

I have been working on a MVC application for the past couple of days. In this I am using couple of dropdownlists and wanted to if what I have done is a good practice. I have around 5-6 dropdowns which are pulled in from the database. There dropdowns have a ID and description field. I am able to get the dropdowns filled in with out a problem. However when I am listing the master table is when I am having performance problem.

All the dropdowns selections are stored as integer in the database so I have the field also as in the BaseModel (Class that is mapped to HBM). When I list all the records from the database, predictably I get a integer in the record. So far I have no issue in the performance.

I wanted to display the description for the selected item so I create a model class for the dropdowns and have a method in the model which will talk to the database and get the description based on the selection. The problem is this is slowing down the page load. I wanted to know if I need to make design change to get this loaded faster. The following is the code I have

MasterList1 Table (State and County are integers in this table) State Dropdown (Master table having all states with ID) County Dropdown (Master table having all counties with ID)

BaseModel Classes for Nhibernate

MasterList1 State County

Model Class

MasterList1Model StateModel CountyModel

Repository Class MasterList1Repo StateRepo CountyRepo

View MasterList1

In the view I am calling a string proprty in the BaseModel class. In the property, I am placing a call to the Model class which in turn places a call to the Repo to get the string. Here is the method in Repo class.

        public ApplicationTypeMaster GetByID(int ID)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            return session.Get<ApplicationTypeMaster>(ID);
        } 
    }

    public string GetApplicationTypeByID(int ID)
    {
        return GetByID(ID).ApplicationTypeDescription.ToString();
    }

I am not sure how to improve this. Any suggestions ?

3
  • Could you add your view code? Commented May 28, 2013 at 8:00
  • The View has model=>model.ApplicationTypeDescription rendered. This property makes a call to the Model class which queries the Collection that I load when page loads. Is this what you were looking for @jeroenk ? Commented May 28, 2013 at 16:11
  • It's really hard to say, your example isn't clear enough. If you could create a sample application and share it on a dropbox share that would be appreciated. One recommendation I could make is to look into NHibernates 2nd level caching in order to reduce requests to the database. You could also consider creating your own in-memory static cache of these objects if they don't really change over time. Can provide you with some more concrete examples if you provide a more thorough description for us. Commented May 29, 2013 at 20:10

3 Answers 3

2
+25

Do you know the ViewModel approuch? It is a class that represents what a View need to show. You can create a ViewModel class with theses proeprties you need and type your Views with this class, fill it with NHibernate and then show it, for sample:

public class ApplicationTypeMasterViewModel
{
   public int Id { get; set; }
   public string Name { get; set; }
   public string CityName { get; set; }
   public string StateName { get; set; }

   // other properties you need

   public ApplicationTypeMasterViewModel() { }   
}

in your Service Layer, try something like this:

public ApplicationTypeMasterViewModel GetByID(int ID)
    {
        using (ISession session = NHibernateHelper.OpenSession())
        {
            return session.Query<ApplicationTypeMaster>()
                            .Fetch(x => x.City).ThenFetch(c => c.State)
                            .Where(x => x.Id == ID)
                            .Select(x => new ApplicationTypeMasterViewModel() { 
                                                    Id = x.Id, 
                                                    Name = x.Name, 
                                                    CityName = x.City.Name, 
                                                    StateName = x.City.State.Name
                                                    // other properties you need
                                            })
                            .FirstOrDefault();
        } 
    }

You could do it using Lists or Single objects.

In the controller you call this method and pass the ViewModel to your View and render it:

<p>
    <label>Name: </labe>
    <%: Model.Name %>
</p>

<p>
    <label>City: </labe>
    <%: Model.CityName %>
</p>


<p>
    <label>State: </labe>
    <%: Model.StateName %>
</p>
Sign up to request clarification or add additional context in comments.

2 Comments

Yes I am aware of the ViewModel approach. However, I did not implement it because it would have bought an additional layer to the current implementation. The crux of the problem is when I try to list 100 records which has 5 such views. It's taking 25 seconds just to list them. I suspect it is because of continous database calls everytime it tries to get the description. To improve this I loaded all the master values to a ICollection and query the collection when I do a list. The load time has now come to 20 seconds. Not sure how I can improve its performance anymore.
Maybe it's executing by lazyLoading, you could try using EargLoading using Fetch, FetchMany extension methods for Nhibernate To Linq and use it to execute a single query on database. See my edits
2

I would start by looking at the big picture and not just at the code.

Do you have this setting turned on in your hibernate.cfg.xml file?

<property name="show_sql">true</property>

You should be looking at the generated SQL to see if both cache levels are working and if your generated SQL is optimal. Your mapping may be doing many queries for each returned row based on your eager or lazy loading settings. You may even have an indexing problem in your database. You may also want to run a trace on the database and see how much data is really being selected and returned and how long the database is taking to do this.

Comments

1

In general, performance on read operations can be a problem when using an ORM. If lazy loading isn't working for you (you should investigate that first), another way to mitigate the problem is to use a custom query for specific read operations which are not performant. You can use NHibernate for that if you want.

Here is an example of a method on a repository which performs a custom query and returns a DTO (HostingItem in this example) with the help of NHibernate:

        public IList<HostingItem> GetHostingItems()
        {
            const string query = @"
                select 
                    c.id,
                    c.name as CustomerName,
                    p.name as ProductName,
                    wl.DomainName
                from
                    WorkOrderLines wl
                inner join 
                    WorkOrders w on w.id = wl.workorder_id
                inner join
                    Customers c on c.id = w.customer_id
                inner join 
                    Products p on p.id = wl.product_id
                where 
                    wl.active = 1 and
                    wl.type = 'HostingProductWorkOrderLine' and
                    parent_id is null and
                    wl.invoice_id is not null";

            return Session.CreateSQLQuery(query)
                .AddScalar("Id", NHibernateUtil.Int32)
                .AddScalar("CustomerName", NHibernateUtil.String)
                .AddScalar("ProductName", NHibernateUtil.String)
                .AddScalar("DomainName", NHibernateUtil.String)
                .SetResultTransformer(Transformers.AliasToBean(typeof (HostingItem)))
                .List<HostingItem>();
        }

    public class HostingItem
    {
        public int Id { get; set; }
        public string CustomerName { get; set; }
        public string DomainName { get; set; }
        public string ProductName { get; set; }
    }

NHibernate will create the list of DTO's for you, you don't need any mappings or anything for this.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.