Interactive
Software Engineering
EiffelStore

[ISE Home] Home ] Release Notes ] Technology Papers ] Installation Notes ] About Eiffel ]


INTRODUCTION

In this documentation, we will describe how to use the EiffelStore library in an Eiffel project.

This library provides a consistent set of classes for writing object oriented Eiffel applications that need to handle persistent objects.

Before using EiffelStore, we suggest that you read this documentation.

 

Technical Information

The library interface consists of two sets:

  1. A set of general purpose classes designed regardless of any data management system used, found in directory : $EIFFEL5/library/store/interface, and that you always need in your universe
  2. Specific classes, referred to by the interface classes, bridging the application to selected data management systems called "handles''.

 
The set of handles may be found:

  • in directory $EIFFEL5/library/store/dbms
  • in directory $EIFFEL5/library/store/dbms/rdbms/{server_name} 
    where {server_name} correspond to a selected relational database 
    management system.

Additional support classes are also needed in your universe regardless of the selected handle. They are located in:

  • directory $EIFFEL5/library/store/support and $EIFFEL5/library/store/dbms/support

Example classes are located in:

  •  $EIFFEL5/examples/store

You can find the user's manual of our previous version of EiffelStore (mostly up-to-date) in pdf format by clicking here. (This manual is more useful more experiments users) 

Our library has been successfully tested with :

  • ODBC 3.0
  • Oracle 8.04 
  • Oracle 8i Entreprise Edition.

However you should be able to use it with Sybase and OpenIngres. As far as ISE's support is concerned we currently only guarantee support for ODBC and Oracle. Users who want to use Sybase or OpenIngres can still do so, but in the past couple of years we have removed them from our officially supported platforms, due essentially to insufficient number of users.

In order to work with EiffelStore you also need to get EiffelTime library.

 

Getting Started

We provide you the necessary files to compile an EiffelStore project. They should be located in the directory $EIFFEL5\library\store\spec\$PLATFORM\lib (for Unix) and $EIFFEL5\library\store\spec\$COMPILER\lib two C libraries objects.

If the required files are not installed, please the following steps:

Before starting the compilation of the C libraries:

  • Make sure the environment variables EIFFEL5 and PLATFORM are set.
  • Make sure that the Database you have chosen is installed
  • Install the C library for the EiffelTime library, click here to have the instructions on how to build it.

Now, you can installl the C libraries. We will describe below the procedure for both Windows and Unix:

  • On Windows: type "make_msc" or "make_bcc"  (Depending which C compiler you are using msc for Microsoft, bcc for Borland) in the following directories:
    • $EIFFEL5/library/store/Clib
    • $EIFFEL5/library/store/dbms/rdbms/(your_Database)/Clib

    Where your_Database is the database you have chosen (Oracle, ODBC, Sybase or Ingres)

  • On Unix: type "finish_freezing -library" in the following directories:
    • $EIFFEL5/library/store/Clib
    • $EIFFEL5/library/store/dbms/rdbms/(your_Database)/Clib 
    • Where your_Database is the database you have chosen (Oracle, ODBC, Sybase or Ingres)

Congratulation, your EiffelStore library has been successfully installed.

Now you can start a new Eiffel Project using EiffelStore.

How to configure your Ace file

In order to use EiffelStore in an Eiffel Project, you have to include in your project, the right clusters and the right external files. Thus, you need to configure your Ace file.

You can get all the information about Ace files here.

You have to include EiffelStore clusters and EiffelTime clusters.

To include the EiffelStore cluster you have to :

  • Include  these clusters one by one: 
    estore_support: "$EIFFEL5\library\store\support";
    estore_interface: "$EIFFEL5\library\store\interface";
    estore_db_support: "$EIFFEL5\library\store\dbms\support";

THEN

You have to include the cluster referring to your database:

  • For Oracle : estore_oracle: "$EIFFEL5\library\store\dbms\rdbms\oracle";
  • For ODBC: estore_odbc: "$EIFFEL5\library\store\dbms\rdbms\odbc";

In order to work with EiffelStore you need the EiffelTime library installed. And so, you need to include its cluster in your Ace file:

time: "$EIFFEL5\library\time";
time_format(time): "$\format";
english_format(time_format): "$\english";

You now have to include all the external files.

  • For Oracle:

You have to include the oci libraries and the C EiffelStore Files. : 
include_path: "$(ORACLE_HOME)\OCI\Include",
                        "$EIFFEL5\library\store\dbms\rdbms\oracle\Clib";

And to include the Oci.lib,oracle_store.lib, datetime.lib and support.lib objects:
objects: "$(ORACLE_HOME)\OCI\lib\msvc\oci.lib",
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\oracle_store.lib",
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\datetime.lib",
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\support.lib";

Remark: This description is valid only under Windows, if you use Unix, the objects are : libsupport.a, liboracle.a, libdatetime.a .
Moreover, the first command which include the OCI C library should be : "-L$(ORACLE_HOME)/lib -lclntsh"

  • For Odbc:

You only need to include the odbc32.lib,odbc_store.lib, datetime.lib, support.lib objects and the C EiffelStore files.
include_path: "$EIFFEL5\library\store\dbms\rdbms\oracle\Clib";

objects: "your_path\odbc32.lib",
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\odbc_store.lib"
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\datetime.lib",
              "$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\support.lib";

Now your Ace file should be configured. However here you can see the Ace file of the Insert example, working with Oracle under Windows. (Check the Ace of the examples if you need to see other Ace file).

System inserter
   
root
	inserter (root_cluster): "make"
default
	assertion (all)
	console_application (yes)
	precompiled ("$EIFFEL5\precomp\spec\$PLATFORM\base")

cluster
	root_cluster: "$EIFFEL5\examples\store\insert";
	estore_examples_objects:"$EIFFEL5\examples\store\Utilities";
	oracle_handle: "$EIFFEL5\examples\store\Utilities\oracle";

		-- EiffelBase
	all base: "$EIFFEL5/library/base"
		exclude
			"desc";"table_eiffel3"
		end

		-- EiffelStore
	estore_support: "$EIFFEL5\library\store\support";
	estore_interface: "$EIFFEL5\library\store\interface";
	estore_db_support: "$EIFFEL5\library\store\dbms\support";
	estore_oracle: "$EIFFEL5\library\store\dbms\rdbms\oracle";

		-- EiffelTime
	time: "$EIFFEL5\library\time";
	time_format(time): "$\format";
	english_format(time_format): "$\english";

external

	include_path:   	"$(EIFFEL5)\library\store\dbms\rdbms\oracle\Clib",
			"$(ORACLE_HOME)\OCI\include"
	object:
			"$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\support.lib",
			"$(EIFFEL5)\library\time\spec\$(COMPILER)\lib\datetime.lib",
			"$(EIFFEL5)\library\store\spec\$(COMPILER)\lib\oracle_store.lib",
			"$(ORACLE_HOME)\OCI\lib\msvc\oci.lib"
end

How connect your Database

To see all the step of connecting to your Database, let's see the init feature of the Insert example:
We use in that case the Oracle example as the connection only ask for a login name and a password.

init is
		-- Init session.
	local
		tmp_string: STRING
	do
			-- Ask for user's name and password
		io.putstring ("Database user authentication:%N")
		io.putstring ("Name: ")
		io.readline
		tmp_string := clone (io.laststring)
		io.putstring ("Password: ")
		io.readline

			-- Set user's name and password
		login (tmp_string, io.laststring)

			-- Initialization of the Relational Database:
			-- This will set various information to perform a correct
			-- connection to the Relational database
		set_base

			-- Create usefull classes
			-- 'session_control' provides information control access and 
			--  the status of the database.
			-- 'base_store' provides updating facilities.
		create session_control.make
		create base_store.make

			-- Start session
		session_control.connect

	ensure
		not (session_control = Void)
		not (base_store = Void)
	end

Now you are connected to your database, and you can perform a query.

How to realize a basic query

To see all the step of a basic query, let's see the make_selection feature of the Select example.

make_selection is
		-- Select books whose author's name match
		-- a specific name.
		-- The name must be written in upper-case letters, and
		-- enclosed in '%' (This caracter is used by SQL to match 
		-- any string of zero or more character)

	local
		author: STRING
	do
		from
			io.putstring ("Author? ('exit' to terminate):")
			io.readline
		until
			-- Terminate?
		io.laststring.is_equal ("exit")

		loop
			author := clone (io.laststring)
			io.putstring ("Seeking for books whose author's name match: ")
			io.putstring (author)
			io.new_line
			io.new_line
				-- A mapped Eiffel object (author) is referred to by a key name
				-- "author_name" which can be used in a SQL statement prepended with ':'
			base_selection.set_map_name (author, "author_name")

				-- Set action to be executed after each 'load_result' iteration step.
				-- 'init' and 'execute' method of the current class are to be used.
			base_selection.set_action (Current)

				-- Query database.
				-- The reference ":author_name" will be changed to the value of
				-- the Eiffel object referred to by the key "author_name".
			base_selection.query ("select * from DB_BOOK where author = :author_name")

				-- Iterate through resulting data, and display them
			base_selection.load_result

				-- Delete "author_name" from the map table
			base_selection.unset_map_name ("author_name")

				-- Terminate the current order
			base_selection.terminate

			io.new_line
			io.putstring ("Author? ('exit' to terminate):")
			io.readline
		end
	end

Thus, to perform a query you need to create a DB_SELECTION object (base_selection in this example). Then you can follow all the steps of this example.

Some Working Examples

We developed 7 Examples that you can try to understand EiffelStore.

They are in the directory : "$EIFFEL5\examples\store"

We recommend you to try the examples in the following order:

  • Esql
        Very useful to test you Database connection.
  • Select
        The basic example for a query of your Database.
  • Insert
        The basic example for an insert in you Database
  • Nesting
        An Example of Nested queries.
  • rm2oom
        From an Relationnal Model to an Object Oriented Model.
  • oo2rm
        From an Object Oriente Model to an Relationnal Model.
  • convert
        to exercise the flat file conversion utilities.

Esql

Make sure that you have read the previous explanations before running this example.

To run esql, you just need to launch : esql.

Then this example illustrates how to access database information.

SQL statements are filtered through a monitor and sent to the RDBMS.

Remarks : Once you made an SQL Statements, you should not ended it using a semi-colon. Indeed, you can do it with Oracle statement but not with ODBC statements.

Select

Make sure that you have read the previous explanations before running this example.

To run this example. launch: book_select

This example illustrates how to perform a select query.

It is very interesting because you can understand the query method of EiffelStore.

Before running this example you have to copy the right file in the W_code directory of your project.

Thus for an Oracle Database, you have to copy data.sql.oracle in W_code and rename it as data.sql.

For an ODBC Database, you have to copy data.sql.odbc in W_code and rename it as data.sql.

For a Sybase Database, you have to copy data.sql.sybase in W_code and rename it as data.sql.

For an Ingres Database, you have to copy data.sql.ingres in W_code and rename it as data.sql.

Insert

Make sure that you have read the previous explanations before running this example.

To run this example launch book_insert.

This example illustrates how Eiffel users may access their selected Database to insert or modify objects in existing tables.

An Eiffel object, say "`a book'', described by class BOOK, is inserted into a repository (instance of class REPOSITORY) defined with `db_book' access key for instance.

The repository name should match an external RDB table named `db_book'.

In the example, the session terminates on unexisting RDB table.

Class DB_CHANGE encapsulates features supporting insertion statements.

SQL insert statements insert new objects into existing repositories (i.e existing RDM tables).

Class DB_CONTROL provides facilities to manage the session, control the DB status, and query the results.

Nesting

Make sure that you have read the previous explanations before running this example.

This example illustrates how to customize actions when retrieved selection Results.

In that way it does two nested queries to retrieve all the tables and all the columns of your Database. 

Rm2oom

Make sure that you have read the previous explanations before running this example.

This example illustrates how RDBS tables can be translated into Eiffel class definitions where features are simply attributes matching the DB table fields.

Class descriptions are printed on standard output.

A specific repository is referred to by a name that should match a RDB table name for which an Eiffel class equivalent is requested.

Oo2rm

Make sure that you have read the previous explanations before running this example.

Object Oriented Model To Relational Model (OOM2RM)

This example illustrates how to dynamically generate the description of a relational schema (with SQL statements)  from the traversal of a network of Eiffel objects.

One Eiffel model sample is given in subdirectory Model1 and serves as the sample to use to generate the relational schema.

To apply the example on a model of your choice, replace in the Ace file reference to the cluster Model1 with a reference to your customized cluster.


Remarks:
Some problems have been encountered when using generic containers classes derived with simple type. To overcome this problem, rather use ARRAY [INTEGER_REF] instead of ARRAY [INTEGER].

Convert

Make sure that you have read the previous explanations before running this example.

This example illustrates the way one can convert Unix flat files into class instances.

Changing a field (it's type or format) in an example.dat file, highlighs the parser error detection mechanism.

When the example has been compiled, put the two files "example1.dat" and "example2.dat" in the directory "EIFGEN/W_CODE" or in "EIFGEN/F_code" directory depending on your type of Eiffel compilation.