Basic techniques

Architecture

The architecture of EldorADO.NET acknowledges the distributed nature of database applications : the application and the database engine live in differentes processes, whose boundaries are expensive to cross.

To optimize process boundary traversals, the application code will interact with two mains components :
  • The RemoteSource, which is a proxy to the actual database, abstracting the actual database engine.
  • The LocalStorage, which is an in-process data cache, used to store temporary entities and reduce the number of queries to the database.

An ObjectContext provides the glue to tie the two components.
GlobalView.gif

Driving forces of this architecture:
  • A simple but powerful query language (allowing joins) is used to query the RemoteSource as well as the LocalStorage, and the ObjectContext
  • Query results bring back either normalized data (entity collections) or unnormalized data (raw DataTable/DataReader containing joins)
  • The LocalStorage performs lazy loading of data for ease of development
  • You can preload data from the RemoteSource to the LocalStorage in order to optimize complex queries on the LocalStorage as well as lazy loading
  • You can query directly from the RemoteSource in scenarios where you want to by-pass the LocalStorage
  • Several ObjectContext objets can live in parallel to help implement nested transactions.

In addition, the dual architecture (LocalStorage/RemoteSource) provides the following advantages
  • No in-memory processing when the database can be used efficiently
  • No costly cache updating when not needed
    • Using DataTables and getting maximum functionality when binding data to a DataGrid
    • Using DataReaders and getting maximum performance in read-only, forward-only scenarios
  • Rich and powerful cache features when data consistency is vital

Creating entities

Entities are created inside the LocalStorage of an ObjectContext. They are temporary, until the ObjectContext is udpated (see below).

	IObjectContext ctx1 = CreateContext();

	Project project = ctx1.LocalStorage.Create<Project>()
	project.Name = "My project";
	project.Budget = 10000;

	Manager manager = (Manager)ctx1.LocalStorage.Create<Manager>();
	manager.Name = "Jocelyn";
	manager.BirthDate = new DateTime("01/12/1970");
	manager.Title = "PM";

	Employee employee1 = (Employee)ctx1.LocalStorage.Create<Employee>();
	employee1.Name = "Quentin";
	employee 1.BirthDate = new DateTime("09/17/2000");

	Employee employee2 = (Employee)ctx1.LocalStorage.Create<Employee>();
	employee2.Name = "Maël";
	employee2.BirthDate = new DateTime("11/12/2001");



Associations between entities

The object model makes it simple to navigate from entity to entity and to create association between entities.
	project.Manager = manager;
	project.Members.Add(employee1);
	project.Members.Add(employee2);

The projects of a particular employee can be enumerated this way :
	// Could use : IList<Project> myStronglyTypedList = employee1.Projects;
	foreach (Project p in employee1.Projects)
	{
		// use p here
	}

Updating the database

Sending the modifications in the LocalStorage to the RemoteSource.
	ctx1.Update();
 

Checking the generated SQL queries

In VisualStudio.NET : View|Other Windows|Output

Querying data from the database

Querying directly toward the RemoteSource
  • you want to see what is in the database regardless of what is in the ObjectContext
  • or you want to get maximum performance by by-passing the LocalStorage.
	IObjectContext ctx2 = CreateContext();
	string query = "select p, p.Name, p.Budget from Project p";
	DataTable table = new DataTable();
	ctx2.RemoteSource.Fill(table, query);

  • The resulting DataTable has 3 columns named p, Name and Budget
  • The first column (p) represents the project’s id.
  • The last two columns (p.Name and p.Budget) represent properties of the Project entity.

Useful for example to bind data to a DataGrid
	DataGrid dataGrid1 = ...;
	dataGrid1.DataSource = table;

Once the data is the DataGrid, user can click on a row and the application may need to retrieve the entity associated with the row. The following paragraph demonstrates how to do so.

Retrieving entities

Querying the ObjectContext by id, and lazy-loading the entity if it is not in already in the LocalStorage. Useful in Web based scenarios, where the ObjectContext used to generate the DataGrid has been discarded.
	IObjectContext ctx3 = CreateContext();

	string projectId = ...;  // from the datagrid, column named "p"

	Project p = ctx3.Find<Project>(projectId);
	float totalAge = 0;
	foreach (Employee e in p.Members)
		totalAge += DateTime.Now - e.BirthDate;
	float average = totalAge / p.Members.Count;
}

More complex queries

Extension of the preceding scenario to include more complex queries, containing joins.
	IObjectContext ctx4 = CreateContext();

	string query = "select p, p.Name, p.Budget, m.Name " +
	"from Project p, p.Manager m " +
	"where m.Name like ? " +
	"order by p.Budget desc";

	DataTable table = new DataTable();
	ctx4.RemoteSource.Fill(table, query, "J%");

Assuming the association between Project and Manager is represented by a foreign key constraint an equivant syntax of the from clause in SQL would be like:
	from
	Project p,
	Manager m on m.ID = p.ManagerID

Had the association between Project and Manager been represented by an associative table, the SQL form would be even more complex:
	from
	Project p,
	Project_Manager pm on pm.ProjectID = p.ID,
	Manager m on m.ID = pm.ManagerID

With SQL the physical model gets in the way of the object developper:
  • The choice of the mecanism used to represent the association – be it a foreign key constraint or an intermediate lookup table – is immediately visible to the query writer.
  • Some unnecessary redundancy is imposed to the developper : e.g. a foreign key constraint already specifies that p.ManagedBy references a Manager and that m.ID = p.ManagedBy. So one should not be forced to specify this kind of information again for each query.
  • The query writer must deal with the idiosyncrasies of SQL dialects (e.g. the join syntax) in multiple database engines scenarios.

With ADOOR’s object query language, you still have the full power of SQL, but at a logical level!!!
  • You query toward the logical (object) model rather than toward the physical (relational) model
  • Projections, joins and other relational operators are still available
  • The query language provides a unifying syntax for all database engines


Last edited Sep 6, 2007 at 9:12 AM by ysaule, version 4

Comments

No comments yet.