In my previous article, I described a scenario where teams of scientists and students would collaborate around some common weather data. We have been tasked with building a software system that allows them all to perform their unique jobs with this set of data. Let's design and create a database that will store the weather data as it is recorded.
Before we dive in, let's think about our design options. If you are not a database administrator or designer, you might be tempted to think of a database as if it were a spreadsheet. After all, database tables have rows and columns, right? If we were to design our database with this paradigm in mind, we might build just one table that contains a column for each type of weather data; perhaps a column for recording the temperature and a column for wind speed. We might also want to collect things like the date of the entry and the name of the scientist who entered the data, so we would create a column for them, too. This type of database is pretty simple to build, and that is what makes it so tempting.
Close your eyes and imagine what will happen if we went down the road with this simple one table design.
|
Related Reading
Cocoa in a Nutshell |
You would probably design and build the database in record time. Everyone in the office would cheer and want to take you to lunch. Development would start immediately on all kinds of cool applications that use the database as a hub. So far, so good. Right? Well doom lurks around the corner. You heard right. Doom!
Six months down the road, thousands of weather samples have been entered into the database and the whole team is deeply focussed on their respective jobs. One of the scientists is about to make a major leap forward in the field of weather prediction! She just needs one little thing. (Uh oh.) Her theory is based on the connection between temperature and atmospheric pressure, but the database is not tracking atmospheric pressure. This new piece of data needs to be collected, stored in the database, and analyzed for all measurements going forward.
Now what are you going to do? It is not as simple as adding an extra field to the table. All of the components that interface with the database will need to be updated, tested, and deployed all over again. And you better make backups, because changing tables in a database full of information sounds risky. At best, things are going to be down for a while, and you are going to have to deal with versioning issues between software, XML, and database schemas. Yuck!
Luckily, you can make decisions today that will avoid your future doom. Instead of hard-coding the measurement types as columns in the database, we will create a table that stores the descriptions of each types as data, not hard-coding it in the schema.
In fact, we will build three tables. The first will hold a list of basic data types that our client applications should know how to validate, such as integer, decimal, and string. The second table will hold measurement types with labels such as temperature, wind speed, and precipitation. Each measurement type will link to a data type. For instance, a temperature could be stored as a decimal number. In other words, the definition of the temperature type would link to the decimal number type. Finally, our third table will store the actual measurements. Each piece of measurement data will have a measurement type associated with it.
With this three-table schema, we will be able to add new measurement types on the fly. We can design our XML and client applications with the same degree of flexibility, which is exactly what we will do in future articles.
Install xCode, WebObjects, and OpenBase
Before we get started, you will have to make sure that you have the required software on your Macintosh. Though the concepts should be applicable on any platform, this tutorial is based on Apple's Xcode and WebObjects, as well as the OpenBase database. You can get free or trial versions of all three applications from the companies that make them (follow the links). Follow the manufacturers' instructions to download and install each of them, and then we will continue with the tutorial.
First create a new database:
Weather and click Create.
There are many tools you can use to build a database, but since we are going to use WebObjects on this project, we will use EOModeler. EOModeler is an application that ships as part of WebObjects and is used to map a database to Java Objects. Conveniently, if we design a database schema in EOModeler, it can generate the SQL code to build the actual database for us.
Here are the steps to creating a new model:jdbc:openbase://localhost/Weather.
Weather.Next, we are going to create the tables discussed in the introduction and implement our design in EOModeler, which is creating a description of the database that we will then use to build the actual database. We're going to go quickly through the steps of creating a model. For more detail on using EOModeler, see Apple's excellent WebObjects documentation on their developer web site.
DataType for the name and DATA_TYPE for the table name. You can leave the class set to the default value of EOGenericRecord.
MeasurementType and table name of MEASUREMENT_TYPE.MeasuredData and a table name of MEASURED_DATA.
|
dataTypeId and the column field to DATA_TYPE_ID. Set the external type to long and the Internal Data Type to Integer.
measuredDataId and measurementTypeId for the names. Use MEASURED_DATA_ID and MEASUREMENT_TYPE_ID for the columns. In each case, make sure the key icon is showing and the diamond icon is not.name and the column to NAME.char and the internal data type to String. When you select String as an internal type, a field will appear that allows you to set an external width. Type 255 in this field.
name attribute to the MeasurementType entity that is identical to the one you just created. In fact, you can use copy and paste to create it, if you want. To do this, select the attribute in the main window and choose copy. Then, select the MeasurementType entity and choose paste.MeasuredData entity. The first one is to store a timestamp for each new piece of data that is entered. Create a new attribute, set its name to timeTaken, the column to TIME_TAKEN, the external type to datetime, and the internal type to Date.MeasuredData entity to store the actual measured data. Since we do not know the type of the data for each row in the database ahead of time, we will set the data column to store a large string. Most other data types can be converted to a string. Set the name of the new attribute to data, the table name to DATA, the external type to char, and the internal data type to String, with an external width of 1024
dataTypeId attribute from the DataType entity and paste it into the MeasurementType entity. This will allow the measurement type to store a link to each row's data type. Set the attribute so that neither the key or diamond icons are showing (because it is not a primary key, and because this attribute will not normally visible to users).dataTypeId that you just pasted into the MeasurementType entity. In the Inspector, view the Advanced Options for this attribute by clicking the second icon in the toolbar of the Inspector. There should be a checkbox to set whether or not to allow null. Make sure that it is checked so that null values will be allowed.
measurementTypeId attribute from the MeasurementType entity and paste it into the MeasuredData table. This allows the measured data to store a link to its respective measurement type. Set the attribute so that neither the key or diamond icons are showing.MeasurementType table and choose Add Relationship from the Property menu.dataType. Select the DataType table in the Entity selector. Then make sure that To One is selected, since there will be one data type for each measurement type. Finally select "dataTypeId" in both of the Join selectors and click connect. This is what it should look like:
measurementType. Select the MeasurementType table in the Entity selector. Make sure that To One is selected, and then select measurementTypeId in both of the Join selectors and click connect.Your database schema is complete. To view it in a nice graphical form, use the icon on the far left of the toolbar to toggle to the table view. Your model should look something like this:

Once our EOModel has been created, it's no problem to create database tables that match the design. EOModeler can create the SQL code for you, and will even apply it to your database using the adaptor information that you specified earlier.
|
If you have completed all of the steps above, you've created a simple, but flexible database for holding weather measurements. Of course, it is not very exciting in its current state. Our database does not even have any data yet! Fortunately there is a cool technology in WebObjects that can automatically build a web application, based on our EOModel, that we can use to populate the database. We will build much better data entry tools in future articles, but this will give us some data to play with as we design the rest of the system.
WeatherHub and click Next.Weather.eomodeld). Then click Next.number in the text box and press Save.
string.
MeasurementType in the pop-up menu on the left side of the browser window. Click the New button.Temperature to the new measurement type.Wind Speed (just like Temperature, its data type is also "number").
MeasuredData as an entity before trying to add new data.70 for May 1, 2004.5 for May 1, 2004.
Congratulations on designing and building a flexible database. We also built an administration tool using WebObjects and entered some data into our new database. Not bad for our first tutorial together! Give yourself a pat on the back if you made it all of the way through. For each article in this series, I will assign some extra credit for those who want to go beyond the tutorial. For this article, it would be nice to have a location associated with each measurement. For extra credit, add another table that stores location data (such as latitude, longitude, and altitude) and create a relationship so that it is connected to the measured data table.
In the next article we'll design an XML format that can be used to transfer all of the data in database. After we do that, we will have our hub and spokes well-defined and we can get into the really fun stuff. Until then, happy programming.
Adam Behringer works as the CEO of Bee Documents, which strives to help legal and medical firms efficiently manage their documents.
Return to the Mac DevCenter
Copyright © 2009 O'Reilly Media, Inc.