The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

MVC trouble

I am having some trouble with my app which is trying to implement MVC.

M is an SQL database (sqlite). V is a grid widget. C fills V with the data it gets from M based on user actions.

When C has to query M and the resultant data is a single item, all is well. C doesn't have to speak SQL at all. It just calls a function of M and gets its data. Trouble breaks out when there are multiple results (rows).

I could think of two ways to transport the data in the rows of the resultant SQL query:

1) Pass the table pointer to C. This is great except now C has to speak SQL and/or know about the details of how sqlite works.

2) Encapsulate the data in a data structure and pass it to C that way or have C create a data object and pass the pointer to M which can fill the object. This way C doesn't have to know about the details of M. This is fine, but it breaks down when I have to have various methods to cover different SQL query scenarios and in the very simple cases, it is too much overhead.

Am I doing something wrong? Overlooking something? How do you suggest I go from here?
coder
Wednesday, October 03, 2007
 
 
My simplistic analysis is that you are ignoring the fact that there are tools for doing all of this for you.  Unless you are working in some obscure language or environment with no support for SQLite, you should be able to find tools that deliver datasets from the database to your grid for you without your having to go through all that trouble.

I don't know about SQLite but Delphi, for instance, has had ADO and other components for SQL Server and several other databases for many years that do exactly what you are describing.
Karl Perry Send private email
Thursday, October 04, 2007
 
 
If M is a SQL database and C fills V with the data it gets from M Then
  C has to know both about the database and its queries, and about the V object
End If
Johncharles Send private email
Thursday, October 04, 2007
 
 
It looks to me that the OP is using C or C++ so datasets and such may be out of reach.

I think that calling your database the model is probably what is breaking your design. Adding a model class or layer in front of your database and creating data structures that can be filled by the model and displayed by the view will solve your problem without having the view know about SQL.

On the other hand, in MVC the view knows about the model anyway so you could expose the result of your query to the view which would then call step (or alike) to get the next rowset and fill your UI. This way you would not need the data structures to transport the data but your view would have to be smarter.
JSD Send private email
Thursday, October 04, 2007
 
 
In MVC - Model View Controller, Model != Database

It is a common misunderstanding.  If you layered up the application into Presentation, Business and Persistence layers, the MVC sits in the Presentation Layer. It is an implementation of how user interacts with data as in business domain object not database data.

MVC of the Business layer, is the Service Patterns where WebService, Rest etc come into play.

MVC of Persistence layer, is JDBC, DAO, etc.
RM
Thursday, October 04, 2007
 
 
> It looks to me that the OP is using C or C++ so datasets
> and such may be out of reach.

Yes I am using C++. No ADO api available at the moment.

> I think that calling your database the model is probably
> what is breaking your design. Adding a model class or
> layer in front of your database and creating data
> structures that can be filled by the model and displayed
> by the view will solve your problem without having the
> view know about SQL.

This is essentially what I am doing with #2. M is a class (CModel) separate from the database. It has a pointer to the database and it acts as a bridge between the database and C. C calls methods of M to access the data in the database, but C does not speak SQL.

As I said, the problem is when there are multiple rows returned by the SQL query. This data already sits in a nice sqlite structure returned by the database. I can expose this structure directly to C which makes life much easier, but I don't know if this is "cheating".

Another issue is coming up with an optimal set of methods for M to be used by C. C isn't allowed to speak SQL, so it calls methods of M. I try to match these methods to the "business logic" and it mostly works, but sometimes I need to pass lots of parameters to M for the SQL query. I guess I'll just have to live with this.

I also considered getting rid of CModel completely and using the database directly, but in some cases CModel centralizes methods for certain common transactions, so it helps in that way.
coder
Thursday, October 04, 2007
 
 
Typically I create a repository class(es) which knows how to retrieve data from a DB. This repository class fills objects corresponding to the tables.

So, as a simple example, I have a Customer table in my database.

I create a Customer class which contains things like:

Name, Address, Order History, etc.

I create CustomerRepository

This class has methods like

Customer[] GetCustomers()
Customer[] GetCustomers( string filter )
Customer GetCustomerById( id )
Save( Customer customer )
Save( Customer[] customers )
etc.

When my controller needs to retrieve customers, I do something like.

Customer[] customers = customerRepository.GetCustomers();
customerView.Customers = customers;

Or whatever. In that way, the View doesn't need to know anything about the DB, it just knows about the model class. The model class doesn't have to know anything about the DB, this is all handled by the repository class.

This breaks down a little bit if you begin to implement lazy loading, but still basically works more or less the same way.

Thursday, October 04, 2007
 
 
anon,

What you suggested sounds very much like my method #2 except I am using data structures instead of data objects. It sounds like I might be better off turning my data structures into data objects (essentially mini-models) and get rid of the monolithic CModel.

How about handling the explosion of model methods in order to hide the raw SQL queries? In your example, let's say each customer has various attributes like name, phone, address, etc.. The application may need to access customer information using different combinations of these attributes. A method in the model will have to cover each case. That's possible, but it somehow feels wrong/reduntant. What can I do to manage the interface optimally?
coder
Thursday, October 04, 2007
 
 
I guess "Customer[] GetCustomers( string filter )" is how you would handle this. Can you elaborate?
coder
Thursday, October 04, 2007
 
 
Lastly, doing what you suggest creates the overhead I was talking about earlier. First, you access the database and fill the Customer class with data. Then you use this Customer class and fill the View (perhaps a grid or tree widget) with data.

I guess this is expected?
coder
Thursday, October 04, 2007
 
 
I don't think that passing the SQLite structure to the view is cheating or in any way wrong. That structure is in fact your data transport method (like a dataset in the .NET world), not to be confused with your data layer. Your data layer is the group of methods that know about SQL plus the SQLite library plus the data file. The output of your data layer is the SQLite structure with all the data returned from the query and it is fed to the view which formats it and shows it on screen. All this orchestrated by the controller.

You could reformat the SQLite structure into an object like the Customers collection above. The good side is that your view will be completely independent of SQLite the bad side is some overhead and more code. It is your call whether you require that flexibility or not.

As for method calls with many parameters I suggest you create a struct or structs that encapsulate those arguments, a bit like the extensions to the EventArgs class in .NET. It is neater and easier to refactor later on.
JSD Send private email
Thursday, October 04, 2007
 
 
Calm down about the "overhead".
Unless you are making what needs to be the most performant application in the world then this trade off is 100% worth it.

If you're _that_ concerned about performance then write the whole thing in assembly.
Jax Send private email
Thursday, October 04, 2007
 
 
Indeed the runtime overhead may be be minimal but the coding and testing overhead will not be. On the other hand the OP may be selecting hundreds of thousands of rows each time and that many news would be noticeable. It really depends.
JSD Send private email
Thursday, October 04, 2007
 
 
Yes I was referring to coding overhead, not runtime performance overhead.

> As for method calls with many parameters I suggest you
> create a struct or structs that encapsulate those
> arguments

I'll try this.

Thanks!
coder
Thursday, October 04, 2007
 
 
As far as how you handle a large number of parameters, most ORM applications support a query language of some kind. This can be as simple as the generally bad

Customer[] GetCustomers( string filter )
{
  query = "SELECT * FROM Customer WHERE " + filter;
  //code to execute the query
}

to things much more advanced like creating a Query object such that you can do something like this:

Query query = new Query(typeof(Customer));
query.AddExpression( "Name", EqualityOperator.Equals, "John Doe");

customerReceiver.GetCustomers( query );

It all depends on how complex you want to make it.

As for the question of if using something like objects vs. DataSets increases overhead, as one poster said, it really shouldn't matter much for most applications.

Personally I think this greatly increases testability since you can more easily write automated unit tests and use mock objects to isolate components. And for me at least, it speeds up coding.

And it doesn't really add too much code depending on your development language. I use .NET, so can take advantage of generics to pretty much use a single Repository structure for all my data access needs.

Then the code looks more like repository.GetAll<Customer>(), etc.

If your language doesn't offer that capability then look at using CodeSmith or MyGeneration to generate your templates. With both applications there are already a ton of data access templates out there to generate your entire object model/data access layer. Or just go with one of the popular ORMs.

Thursday, October 04, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz