SQL databases, persistence, and objects

When using SQLite, our application works with an implicit access layer based on the SQL language. The SQL language is a legacy from an era when object-oriented programming was a rarity. It is heavily biased toward procedural programming. The row-and-column concepts of relational design creates what's termed an impedance mismatch with the more complex object model of data. Within SQL databases, we generally focus on three tiers of data modeling, which are shown here:

  • The conceptual model: These are the entities and relationships implied by the SQL model. These may not be the tables and columns, but may be views of tables and columns. The views may involve selecting rows, projecting columns, or joining multiple tables into the conceptual result. In most cases, the conceptual model can map to Python objects and should correspond with the data model layer of the application tier. This is the place where an Object-Relational Mapping (ORM) layer is useful.
  • The logical model: These are the tables, rows, and columns that appear to be in the SQL database. We'll address these entities in our SQL data manipulation statements. We say that these appear to exist because the tables and columns are implemented by a physical model that may be somewhat different from the objects defined in the database schema. The results of an SQL query, for example, look table-like, but may not involve storage that parallels the storage of any single, defined table.
  • The physical model: These are the files, blocks, pages, bits, and bytes of persistent physical storage. These entities are defined by the administrative SQL statements. In some more complex database products, we can exercise some control over the physical model of the data to further tweak the performance. In SQLite, however, we have almost no control over this.

We are confronted with a number of design decisions when using SQL databases. Perhaps the most important one is deciding how to cover the impedance mismatch. How do we handle the mapping between SQL's legacy data model to a Python object model? The following are three common strategies:

  • Minimal mapping to Python: This means that we won't build Python objects from the rows retrieved from the database. The application will work entirely within the SQL framework of independent atomic data elements and processing functions. Following this approach tends to avoid a deep emphasis on object-oriented programming. This approach limits us to the four essential SQLite types of NULL, INTEGER, REAL, and TEXT, plus the Python additions of datetime.date and datetime.datetime. While this can be difficult for more complex applications, it is appropriate for certain kinds of scripts when doing database maintenance and support.
  • Manual mapping to Python: We can define an access layer to map between our Python class definitions and the SQL logical model of tables, columns, rows, and keys. For some specialized purposes, this may be necessary.
  • ORM layer: We can download and install an ORM layer to handle the mapping between Python objects and the SQL logical model. There are a large number of ORM choices; we'll look at SQLAlchemy as a representative example. An ORM layer is often the simplest and most general approach. 

We'll look at all three choices in the following examples. Before we can look at the mappings from SQL to objects, we'll look at the SQL logical model in some detail and cover the no-mapping, pure SQL design strategy first.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset