0

I'm currently developing my coding skills by practicing Object Oriented Programming.

I am working with a lot of SQL connections in order to retrieve information to initialize my class objects. I believe I am not doing well though, due to the amount of SQL connections I initialize at the same time. I often need to run several connections at the same time in order to complete initializing my main class. Below is a short example of what I mean.

I have got several classes. Each class has several properties of a different class type. Here's a short example of how it looks mostly:

public class UserAccount
{
    public long UserId { get; set; }
    public string UserName { get; set; }
    public Address UserAddress { get; set;}
}
public class UserAddress
{
    public long AddressId { get; set; }
    public string Address { get; set; }
}

Now, in order to retrieve information about each one of these classes, I am using specific methods which extract the value of each class property from my database. Here is how my method looks for the class UserAccount:

public static UserAccount GetUserAccountById(long id)
{
    UserAccount result = null;
    using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connectionString"].ConnectionString))
    {
        using (SqlCommand cmd = new SqlCommand(string.Empty, con))
        {
            cmd.CommandText = "SELECT * FROM UserAccounts WHERE UserId = @Id";
            cmd.Parameters.AddWithValue("@Id", id);
            con.Open();
            using (SqlDataReader reader = cmd.ExecuteReader())
            {
                if (reader.Read())
                    result = RetrieveFromDatabaseRow(reader);
            }
            con.Close();
        }
    }
    return result;
}
public static UserAccount RetrieveFromDatabaseRow(SqlDataReader reader)
{
    try
    {
        return new UserAccount
        {
            UserId = (long)reader["UserId"],
            UserName = (string)reader["UserName"],
            UserAddress = UserAddress.GetUserAddressById((long)reader["PrimaryAddressId"])
        };
    }
    catch (Exception unhandledException)
    {
        GlobalMethods.LogException(unhandledException);
        return null;
    }
}

Now the UserAddress.GetUserAddressById method is pretty much the same as the extraction method of my first class. It initializes a connection and runs an SQL command.

Why do I think I'm doing it wrong: The current way it's being executing at this point causes several SQL connections to be open at the same time (in my example it's only 2, but there's many more in my actual project).

I was thinking about making one huge SQL statement which joins all of the needed SQL tables in one single command, and then extracts all of that information in order to initialize the main class without requesting additional information from its properties (the UserAddress class for instance). But then it's not funny good to me because often I need to retrieve much information at the same time, and sometimes one statement won't be enough. Besides, it's a pain in the ass to write one heck of a huge SQL statement which JOINs ten tables.

I was thinking about making one global SqlConnection variables which will be initialized only once, and all of my SQL queries will go through him all the time, at the same time. I don't know how it would react to such actions, though.

I could use some tips and hints on how to execute this properly. Thank you in advance.

2
  • I think the problem is that you are querying for each user instead of just getting all users at once, or making a list of users that you need to get and send one query with that in mind Commented Oct 28, 2014 at 12:35
  • @Vajura This example shows how I handle one instance. I've got a similar function which extracts all of the users from the database and adds each one of them to a generic list. However the same "RetrieveFromDatabaseRow" method is in play (in order to initialize the actual User object). Commented Oct 28, 2014 at 12:40

2 Answers 2

1

I was thinking about making one huge SQL statement which joins all of the needed SQL tables in one single command

Probably not a good idea for the very reason you mentioned - you are asking for much more data than is necessary. Plus you would have to maintain that statement every time your data schema changed

I was thinking about making one global SqlConnection variables which will be initialized only once, and all of my SQL queries will go through him all the time, at the same time.

Again, not a great idea. SQL Connections are pooled, so creating them is generally not very expensive. Also, "global" variables can reduce testability and add dependencies to your design that are not easily removed.

Your pattern is pretty typical for a low-level SQL repository. The general pattern is:

  1. Build the SQL statement
  2. Create/open the connection
  3. Create the SQL command
  4. Execute the SQL command
  5. Translate the results to a data structure (DataTable/collection of objects)
  6. Return the data structure

You could possible rafactor the code to enable some reuse, but that's about as low as you can get,m since every SQL commandis different and may require special handling (parameters, transactions, etc.)

Also, having multiple special-purpose SQL statements has some advantages, including:

  • Efficiency - only ask for the data that is needed
  • Isolation - if you change the schema of one table you only have to change the commands that are directly affected
  • Modularity - it would be more straightforward to change the source of one entity if necessary

Edit based on comments

It sounds like you're looking at two extremes - one end is pulling each object separately (10 queries) and another is pulling everything and cherry-picking which data you want to keep. There are probably times when you want to pull a few tables at one time, which is easily doable with SQL statements without having one monolithic SQL statement that all queries use.

An example would be a query that joins UserAccount and UserAddress, then creates multiple objects from the results. That is perfectly valid and can be done with the pattern you are using without needing one giant query to pull ALL possible data.

ORMs like Entity Framework do this sort of thing all the time, but when it gets down to the actual database connection it uses a pattern similar to what you're using - create a connection, create a command, execute it, hydrate the results, close the connection.

Sign up to request clarification or add additional context in comments.

7 Comments

So what is your suggestion? I mean you summed up pretty much what I wrote on my main post. How do I handle this thing, then? What's happening on huge systems, an e-commerce type-of-system, for example? How do they manage to pull this off?
My suggestion is to stick with the pattern you have - or at the least to not make the two changes that you proposed. You only sense that something is wrong - do you have any concrete problems that you are trying to solve? Where do you see that several commands are open at the same time? Why is that a problem?
Also recognize that connections are pooled by .NET, so creating one is typically a very cheap action, and multiple connection objects does not necessarily mean multiple actual database connections.
I get your point, however - what about the fact that I can end up making up to ten queries to the database per object (depending on its structure) rather than having one big query to select all of the information I need? Would that be much of a difference when it comes to speed and performance? Keep in mind that I would often need to select many objects at once and not just one - meaning I can run those 10 queries I need in order to initialize one object up to 1000 times, if my user list is that big.
Also to your edit on your answer - it seems okay and quite easy when it comes to 2 database tables joined via one single query, however, I've got many more. I listed these two for demonstration purposes only so it's fast for others to understand what I am talking about.
|
0

What you are doing looks like what Linq gives you, the main difference being not having "Live" database query backed properties, but one method that internally populates all the properties in one go.

I suggest you take a close look at an existing framework like Linq to SQL or Linq to Entities (Entity Framework)

3 Comments

As you can see in the code I have provided - I am using the 'using' statements each time I initialize a connection, even when I initialize a command. How would you suggest working with the global connection, though? Given the fact I am developing an ASP.NET based website - where would I put the so called connection variable?
Yeah, I didn't notice they were all properties at first, fixed that
Ouch, nor did I notice ASP.NET, create ONE connection per request, what per request means depends on the version of ASP.NET you are using.

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.