Creating an Online Exam Using LINQ to Classes Part 1
By AzamSharp
Views: 8534

Introduction:

Few months back I wrote an article in which I talked about creating an online exam using NHibernate. In this article I will use LINQ to Classes to create the online exam. This is a multi-series article and in this part I will discuss the architecture and the design of the application.

Application Requirement:

The client needs an application where students can log in and give the exam. The exam is uploaded using an XML file provided by the client. The user will take the exam then view his scores.

I will not discuss the user login and authentication section and will focus on the exam modules.

Database Design:

The database name is “School” and it consists of five tables. Take a look at the database diagram shown below:

 

Users: This table holds the users.
Exams: This table holds the exams.
Questions: This table holds the questions of the exams.
Choices: This table holds the choices of the questions.
UserExams: This table holds the user grade and score of the exams.

Class Diagram:

LINQ to Classes allows you to create classes using the database tables. Simply, drag and drop the table from the server explorer on the design view and it will automatically create the class diagram. Take a look at the entity class diagram below:

 


Apart from the entity class diagram I have also included the Repository and Services class diagram. This one is a big diagram so don’t be scared! 


 
Let me explain the architecture of the repositories. Each aggregate root has its own repository. Exam has ExamRepository, User has UserRepository etc. There are no repositories for Question and Choices. This is because they are handled by the ExamRepository.

Each repository inherits from the particular repository interface and the BaseRepository class. Every concrete repository inherits from the base repository interface called IBaseRepository. This is because each concrete repository i.e. ExamRepository, UserRepository must expose some common methods like GetById, Add, PersistAll, GetAll. If I put these methods in the corresponding repository interfaces then I have to implement those interfaces in the concrete repositories which, means repetitive code.

The BaseRepository comes to the rescue and implements the common methods exposed by all the repositories. The methods are also marked as virtual so they can be overridden in the sub repositories.

Let’s take a look at the IBaseRepository interface.

public interface IBaseRepository
    {
        T GetById<T>(int id) where T : class;
        void Add<T>(T item) where T : class;
        void PersistAll();
        void AddAndPersistAll<T>(T item) where T : class;
    }

As, you can see the IBaseRepository interface works with the generic type T.  I will explain the purpose of using the constraints later in this article. Now, let’s see the implementation of the generic GetById method implemented in BaseRepository class.

     public T GetById<T>(int id) where T : class
        {
            var table = school.GetTable<T>();

            // finding the name of the PK column in the database
            MetaModel mapping = table.Context.Mapping;
            ReadOnlyCollection<MetaDataMember> members = mapping.GetMetaType(typeof(T)).DataMembers;

            string pk = (members.Single<MetaDataMember>(m => m.IsPrimaryKey)).Name;

            // getting the object by Id
            return table.SingleOrDefault<T>
                (delegate(T t)
                {
                    int memberId = (int)t.GetType().GetProperty(pk).GetValue(t, null);
                    return memberId == id;

                });                   
        }

The GetById method above looks little complicated but I will try my best to explain it. First, let’s talk about the constraint as shown below:

public T GetById<T>(int id) where T : class

The constraint says that the type T must be a class. This is because the method school.GetTable<T>() only works on the reference types. The purpose of GetById method is to return the object based on its Id. The problem is that each entity class has a different name for its primary key column. User class has UserID, Exam class has ExamID and so on. This makes things more complicated as we have to find the name of the column which serves as the primary key. For this I am using the following code which finds all the columns of the table and then finds the column name which serves as the primary key.

            // finding the name of the PK column in the database
            MetaModel mapping = table.Context.Mapping;
            ReadOnlyCollection<MetaDataMember> members = mapping.GetMetaType(typeof(T)).DataMembers;

            string pk = (members.Single<MetaDataMember>(m => m.IsPrimaryKey)).Name;

Once, we got the primary key can extract the value out of that column and compare with our passed parameter “id” as shown below:

            return table.SingleOrDefault<T>
                (delegate(T t)
                {
                    int memberId = (int)t.GetType().GetProperty(pk).GetValue(t, null);
                    return memberId == id;

                });                   

There is a performance hit when using the above approach since we are using reflection to find the value. But this was a trade off I took over writing repetitive code.

Let’s also take a look at the other three BaseRepository methods.

public void Add<T>(T item) where T : class
        {
            var table = school.GetTable<T>();
            table.InsertOnSubmit(item);
        }

        public void PersistAll()
        {
            school.SubmitChanges();
        }

        public void AddAndPersistAll<T>(T item) where T : class
        {
            var table = school.GetTable<T>();
            table.InsertOnSubmit(item);
            PersistAll();
        }

The Add<T>(T item) method adds the item to the table collection but does not commit it to the database. The PersistAll method commits the item to the database. And finally the AddAndPersistAll method add and persist the item in the database.

Conclusion:

In this article we discussed the architecture of the online exam application. In the next article we will write some unit tests to test our domain layer and the repositories.

The download will be provided in the next part of this series.

By AzamSharp


Enter Comment/Feedback
  •  
  •  
  •  
  •  
  •  

Comments/Feedbacks
Subject: Excellent site
Name: Stephen Bridgett
Date: 12/20/2007 4:29:29 AM
Comment:
I have just discovered your site after searching for help on using an ObjectDataSource.
Subject: RE: Excellent Site
Name: AzamSharp
Date: 1/5/2008 9:00:15 PM
Comment:
Hi Stephen Bridgett, I am glad you enjoyed the website. :)
Subject: ask
Name: quachnguyen
Date: 1/23/2008 12:05:09 PM
Comment:
What's data type of some fields of table ?such as Question table.
Subject: RE: ASK
Name: AzamSharp
Date: 1/23/2008 1:36:36 PM
Comment:
Hi quachnguyen, Nothing complicated! QuestionID, ExamID is the integer fields. Text is a [TEXT] field and Point is a decimal field.
Subject: Repositories
Name: jon
Date: 1/23/2008 3:03:57 PM
Comment:
Hi Azam, I am trying to understand 'repositories', what they are and how to use them. Could you recommend any further reading. Many thanks. ps could you make this comment box multi-line with text wrapping!
Subject: RE: Repositories
Name: AzamSharp
Date: 1/23/2008 4:31:54 PM
Comment:
Hi Jon, Repositories acts a container for your domain objects. This means instead of going to the database you can use repositories to get the item(object) from the memory. Check out the following book: http://www.amazon.com/Enterprise-Application-Architecture-Addison-Wesley-Signature/dp/0321127420/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1201134473&sr=8-1 PS: I will fix the multi-line problem. Thanks for pointing it out!
Subject: Software Requirement
Name: DotNetGuru
Date: 1/23/2008 7:42:55 PM
Comment:
Azam nice article. Will you tell what software are you using. I want the same app developed using VS2005 and SQLServer2005. For LINQ, what do i have to install...
Subject: good
Name: aspnetx
Date: 1/24/2008 12:39:07 AM
Comment:
Good.
Waiting for the next part.
Subject: RE: Software Requirement
Name: AzamSharp
Date: 1/24/2008 9:09:39 AM
Comment:
Hi DotNetGuru, I am using VS 2008, SQL SERVER 2000. Thanks,
Subject: RE: Next Part
Name: AzamSharp
Date: 1/24/2008 9:10:37 AM
Comment:
Hi, Hopefully, I will upload the next part this weekend.
Subject: xweb
Name: supriyo
Date: 1/25/2008 2:31:42 AM
Comment:
good
Subject: Ling to Classes
Name: Francois
Date: 1/28/2008 1:51:07 PM
Comment:
When you talk about LINQ to Classes, is it the same thing as LINQ to Entities/ the Entity Framework?
Subject: RE: Linq to Classes
Name: AzamSharp
Date: 1/29/2008 8:29:23 AM
Comment:
Hi Francois, Linq to classes is separate from the Linq to entities framework/the entity framework.
Subject: Then where...
Name: Francois
Date: 1/29/2008 12:20:16 PM
Comment:
I see. There how do you get to the LINQ to Classes design surface? I may be blind, but I cannot find it...and googling for it doesn't return much... so I"m a bit at a loss :)

I'm probably missing something obvious.
Subject: RE: Then Where
Name: AzamSharp
Date: 1/29/2008 6:30:51 PM
Comment:
Hi Francois, I am using VS 2008. Add a new item and then add a "Linq to Classes" using the add new item. From there you can select "Server Explorer" and drop the tables you need on the design surface.
Subject: I think I figured it
Name: Francois
Date: 1/30/2008 3:55:12 PM
Comment:
Googling around, the only references to LINQ to Classes i have found are, well, all pointing to this site...

From looking at other articles you have written, and from your current description, all I can think of, is that you are refering to "LINQ to SQL".

Either that, or I'm really confused. (I have Visual Studio 2008 too)
Subject: RE: I think I figured it out
Name: AzamSharp
Date: 1/30/2008 5:48:24 PM
Comment:
Hi Francois, Darn! I think I missed one word that caused the whole confusion. It is "Linq to SQL Classes".
Subject: Quid VB?
Name: Etienne
Date: 2/4/2008 11:31:37 PM
Comment:
Greetings,

I have been watching and noticing that you and increasingly many other developers are switching from VB to C# and it's variants.

Do you think there's that much future left for VB?

cheers,

Etienne

Subject: Airlines System Support
Name: Miguel Alonso
Date: 2/5/2008 8:37:24 AM
Comment:
Great and Excellent Site ¡¡, I am going to share it with all of my co-workers

Subject: RE: Quid VB
Name: AzamSharp
Date: 2/6/2008 10:20:44 AM
Comment:
Hi Etienne, I don't think there is anything wrong with VB.NET. The only reason I program in C# is because I am from a C background.
Subject: LINQ DB NULL
Name: Venu
Date: 3/4/2008 5:26:10 AM
Comment:
Hi,
Let me know if we can check the columns in a table allows null values or not using LINQ.
Subject: Nice Stuff
Name: ankur
Date: 3/5/2008 9:36:53 PM
Comment:
Nice article dear
but provide some details for the database table elements eg:point and also provide a bit code in C# also
Subject: Satified site
Name: REVATHI
Date: 5/29/2008 1:58:58 AM
Comment:

When you talk about LINQ to Classes, is it the same thing as LINQ to Entities/ the Entity Framework?
Subject: RE: Satisfied Site
Name: AzamSharp
Date: 5/30/2008 5:14:18 PM
Comment:
Hi REVATHI,

I meant LINQ to SQL.
Subject: Comment
Name: Deepak
Date: 6/17/2008 7:01:55 PM
Comment:
Hi i'm deepak, I find that this site is very useful for me



Join WebHost4Life.com






Copyright GridViewGuy 2007-2008