Java developer-oriented guide to db4o: Part 4: Beyond Simple Object

sponsored links
So far, we have created and operated by db4o object appears relatively simple - a matter of fact, even a bit too simple. This article, db4o active in the Ted Neward will go beyond these simple object, he will show a simple structure of the object (object reference object) when the operation took place. In addition, he also described, including the infinite recursion, cascading behavior, and cited a number of topics, including consistency.


For some time now, in the Java developer-oriented guide to db4o I see a variety of Java to use db4o object storage methods, these methods do not rely on the mapping file. The use of native object database is to avoid one of the strengths of object-relational mapping (perhaps this is not the focus), but I have used the advantages of this object model is too simple, the vast majority of enterprises to create and operate the system requirements for very complex objects, also known as structured objects, this paper will discuss the creation of structured objects.

Basically, the structure of the object can be seen as a reference the object of other objects. Despite the db4o object of the structure to allow the implementation of all the common CRUD operations, but users have to endure a certain degree of complexity. This article will explore the complexities of some of the key (such as infinite recursion, cascading behavior and consistency of reference), since the article will explore more deeply the structure of high-level object dealing with problems. As a supplement, I will also present the test detectors (exploration test): a little known test of the db4o API class libraries and testing technology.

From the simple to the structure of

1 Restatement of the db4o introduced when I have been using a simple type Person:

List 1. Person

                
package com.tedneward.model;

public class Person
{
    public Person()
    { }
    public Person(String firstName, String lastName, int age, Mood mood)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.mood = mood;
    }
    
    public String getFirstName() { return firstName; }
    public void setFirstName(String value) { firstName = value; }
    
    public String getLastName() { return lastName; }
    public void setLastName(String value) { lastName = value; }
    
    public int getAge() { return age; }
    public void setAge(int value) { age = value; }
    
    public Mood getMood() { return mood; }
    public void setMood(Mood value) { mood = value; }

    public String toString()
    {
        return 
            "[Person: " +
            "firstName = " + firstName + " " +
            "lastName = " + lastName + " " +
            "age = " + age + " " + 
            "mood = " + mood +
            "]";
    }
    
    public boolean equals(Object rhs)
    {
        if (rhs == this)
            return true;
        
        if (!(rhs instanceof Person))
            return false;
        
        Person other = (Person)rhs;
        return (this.firstName.equals(other.firstName) &&
                this.lastName.equals(other.lastName) &&
                this.age == other.age);
    }
    
    private String firstName;
    private String lastName;
    private int age;
    private Mood mood;
}


String System OODBMS
You may also recall that in my previous article example, Person the type of use as a field String. In Java and. NET-ri, String is an object type, inherited from the Object, it seems somewhat contradictory. In fact, including the vast majority of db4o, including OODBMS system in the treatment of other objects with String different, especially for non-String change (immutable) characteristics.

This simple type of Person introduced in the basic db4o for storage, query and retrieve data when the effective operation, but it can not satisfy the real-world complexity of enterprise programming. For example, the database address Person family is normal. In some cases, it may be necessary to spouses and children.

Riga in the database to a "Spouse" field, which means that it's an extension to Person, it can invoke the object Spouse. Business rules in accordance with certain assumptions, but also need to add a Gender enumeration types and their corresponding modification method, and add a constructor method equals(). 2 in the list, Person type field with a spouse and the corresponding get / set methods, when attached to certain business rules:

List 2. The person to the right age for marriage?

                
package com.tedneward.model;
public class Person {
    // . . .

    public Person getSpouse() { return spouse; }
    public void setSpouse(Person value) { 
        // A few business rules
        if (spouse != null)
            throw new IllegalArgumentException("Already married!");
        
        if (value.getSpouse() != null && value.getSpouse() != this)
            throw new IllegalArgumentException("Already married!");
            
        spouse = value; 
        
        // Highly sexist business rule
        if (gender == Gender.FEMALE)
            this.setLastName(value.getLastName());

        // Make marriage reflexive, if it's not already set that way
        if (value.getSpouse() != this)
            value.setSpouse(this);
    }
    
    private Person spouse;    
}


3 of the code list to create the two reached the age of Person, code and you expected is very close to:

List 3. To the hall to get married ... ...

                
import java.util.*;
import com.db4o.*;
import com.db4o.query.*;
import com.tedneward.model.*;

public class App
{
    public static void main(String[] args)
        throws Exception
    {
        ObjectContainer db = null;
        try
        {
            db = Db4o.openFile("persons.data");

            Person ben = new Person("Ben", "Galbraith", 
                Gender.MALE, 29, Mood.HAPPY);
            Person jess = new Person("Jessica", "Smith", 
                Gender.FEMALE, 29, Mood.HAPPY);
            
            ben.setSpouse(jess);
            
            System.out.println(ben);
            System.out.println(jess);
            
            db.set(ben);
            
            db.commit();
            
            List<Person> maleGalbraiths = 
                db.query(new Predicate<Person>() {
                    public boolean match(Person candidate) {
                        return candidate.getLastName().equals("Galbraith") &&
                                candidate.getGender().equals(Gender.MALE);
                    }
                });
            for (Person p : maleGalbraiths)
            {
                System.out.println("Found " + p);
            }
        }
        finally
        {
            if (db != null)
                db.close(); 
        }
    }
}


Began to become complicated

In addition to the operational rules of hate, there are several important cases have emerged. First of all, when the object to the database after ben storage, OODBMS store an object in addition to outside, it is clear that a number of other things to do. Search again ben object, associated with the spouse not only store information but also automatically search.

About this series <br /> information storage and retrieval as synonymous with the RDBMS has been more than 10 years, but the situation has changed now. Java developers for so-called object-relational impedance mismatch to despair, no longer have the patience to try to solve this problem. Coupled with the emergence of a viable alternative, which has led to persistence of the object and retrieve the recovery of interest. Java developer-oriented guide to db4o Db4o open source database on introduced, db4o can take full advantage of the current object-oriented languages, systems and concepts. Visit db4o page Download db4o. You need to use it to complete the examples in this article.

To think about, it has a terrible suggestion. Although OODBMS can imagine how to avoid infinite recursion is a scene, but also the problem of terrorism lies in the fact that an object has the idea to other dozens, hundreds of reference objects, each object also has cited its own against other objects reference. Model may wish to consider that children, parents, etc. scenarios. Is only removed from the database will lead to a Person dates back to the source of all human beings. This means that the transmission on the network a large number of objects!

Fortunately, in addition to those the most primitive OODBMS, almost all of OODBMS have solved the problem, db4o is no exception.

db4o tests of detectors

Db4o study of this field is a difficult task, but also gave me an opportunity to show a friend taught me the strategies: exploratory testing. (Thanks to Stu Halloway, as far as I know, he was the first person to develop the argument.) Detectors and test summary, it is a series of unit testing, testing not only the database of unknown origin, but also explore the API to ensure that the library acts expectations. The method has a useful side effect of the base version of the future detectors can be put to test the code, compile and test. If the code does not compile or can not test all the detectors, would clearly mean that the Treasury did not do backwards compatibility, you can used in the production of the system aware of this problem before.

Db4o API to test the detectors and allows me to use a "before" method to create the database and used to fill Person database, and use the "after" method to delete the database and the elimination of the testing process of the miscarriage of justice occurred (false positive). If not, remember that I will have to manually delete each file persons.data. Frankly speaking, I do not believe that their time in exploring API can always remember.

I db4o detectors in test mode in the console database using the JUnit 4 test. Before writing any test code, StructuredObjectTest list of categories, such as 4 follows:

List 4. The impact of the db4o API test

                
import java.io.*;
import java.util.*;
import com.db4o.*;
import com.db4o.query.*;
import com.tedneward.model.*;

import org.junit.Before;
import org.junit.After; 
import org.junit.Ignore; 
import org.junit.Test; 
import static org.junit.Assert.*;

public class StructuredObjectsTest
{
    ObjectContainer db;

    @Before public void prepareDatabase()
    {
        db = Db4o.openFile("persons.data");

        Person ben = new Person("Ben", "Galbraith", 
            Gender.MALE, 29, Mood.HAPPY);
        Person jess = new Person("Jessica", "Smith", 
            Gender.FEMALE, 29, Mood.HAPPY);
    
        ben.setSpouse(jess);
    
        db.set(ben);
    
        db.commit();
    }
    
    @After public void deleteDatabase()
    {
        db.close();
        new File("persons.data").delete();
    }


    @Test public void testSimpleRetrieval()
    {
        List<Person> maleGalbraiths = 
            db.query(new Predicate<Person>() {
                public boolean match(Person candidate) {
                    return candidate.getLastName().equals("Galbraith") &&
                            candidate.getGender().equals(Gender.MALE);
                }
            });
            
        // Should only have one in the returned set
        assertEquals(maleGalbraiths.size(), 1);

        // (Shouldn't display to the console in a unit test, but this is an
        // exploration test, not a real unit test)
        for (Person p : maleGalbraiths)
        {
            System.out.println("Found " + p);
        }
    }
}


Naturally, for this test run JUnit test runner will be expected to generate output: either the ".", Or the green article, which is chosen to test run on the device (console or GUI). Note that generally do not write data to the console - that should be used for authentication, rather than the eye - but in the exploratory test, the do take a look at that data before it is a good idea. What if there is not, I can always comment out the call System.out.println. (Free to add, to test you want to test other characteristics of db4o API.)

From here, on the assumption that the list of test suite 4 contains sample code and test methods (by the method signature specified in the Notes @Test.).






Access to the structure of the object

Storage structure of the object to a large extent as in the case of most of the past: on the object to call db.set(), OODBMS responsible for the remaining work. set() of which object to call is not important, since the adoption of OODBMS object identifier (OID) for object tracking (see "Java developer-oriented guide to db4o: query, update and consistency
"), It would not object to the same store twice.

Retrieving structured objects makes me shudder. If you want to retrieve the object (whether through the original query or QBE) has cited a large number of objects, each object also cited a large number of object reference, and so on. This is a bit like a bad Ponzi model, is not it?

To avoid infinite recursion

The majority of developers regardless of the initial response (usually "can not be such a right, is it?"), The infinite recursion, in a sense to deal with db4o is structured the way the real object. In fact, the vast majority of programmers in this way is hope, because we all want in the search for the object created, they just "out there." At the same time, we obviously do not want to get through a cable message the whole world, at least not once been.

db4o has adopted a compromise to limit the number of objects retrieved by the use of depth as the activation (activation depth) of the method, which specifies the object graph in the lowest level search. In other words, the activation of the depth from the root object that identifies the total number of references, db4o will traverse in the query and return the results of the root object. In the previous example, when Ben retrieval, the default activation depth of 5 for the retrieval of adequate Jessica, because it needs only a reference traversal. Ben any distance more than five references to the object can not be retrieved, they put the quote is empty. My job is to explicitly activate those objects from the database, activate() methods used in ObjectContainer.

If you want to change the default activation depth, the need for a sophisticated way, in the category Configuration (from db.configure() return to) the use of db4o's activationDepth() method to modify the default values. There is also a way to activate the configuration for each depth category. 5 in the list, use ObjectClass default configuration for the type of activation Person depth:

List of 5. ObjectClass configured to activate the use of depth

                
// See ObjectClass for more info
Configuration config = Db4o.configure();
ObjectClass oc = config.objectClass("com.tedneward.model.Person");
oc.minimumActivationDepth(10);







Update the structure of the object

Update of concern is a separate issue: If the object graph to update an object, but did not explicitly set up to do, then what will happen? set() as the initial call, it will be stored in other storage object reference of the relevant object, which is similar to an object when passed to ObjectContainer, db4o traverse all the references will be found in storage to the database object, such as a list of 6 below:

List 6. Updated object cited

                
@Test public void testDependentUpdate()
{
    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
        
    Person ben = maleGalbraiths.get(0);
        
    // Happy birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}


Although the target has done a jess changes, ben object also has references to jess. Therefore jess Person memory stored in the update database.

In fact, this is not the case. Yes, I was lying.

Miscarriage of justice test

The fact is that detectors and test problems in a certain place, and resulted in a miscarriage of justice. Although not obvious from the document view, ObjectContainer maintain the cache object has been activated, so when the list of 6 test Jessica retrieved from the container object, the return of the changes in memory that contains the object, rather than a real disk write data. This is to cover up the fact that certain types of default update depth of 1 means that the only primitive values (including String) in the call will be stored when set(). In order to make the entry into force of the act, I have slightly changed a bit testing, such as a list of 7 follows:

List of 7. Test misjudgment

                
@Test(expected=AssertionError.class)
public void testDependentUpdate()
{
    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
            
    Person ben = maleGalbraiths.get(0);
    assertTrue(ben.getSpouse().getAge() == 29);
    
    // Happy Birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();
        
    // Close the ObjectContainer, then re-open it
    db.close();
    db = Db4o.openFile("persons.data");

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}


Tests, to be AssertionFailure, that the previous target figure of the cascading start to update the object of the thesis is wrong. (Hope you dished out by the type of abnormal types of the value of the Notes @Test set to expected, can be predicted in advance so that JUit this error.)

Cascading behavior settings

Db4o simply return the cached object, rather than its more implicit way to deal with, this is a controversial topic. Many programmers believe that such an act or is harmful and contrary to intuition, or is such an act should be done OODBMS. Do not worry about the merits of how these two views, it is important to understand the default behavior of the database and know how to fix. 8 in the list, use the method of ObjectClass.setCascadeOnUpdate() a particular type of change the default update action db4o. However, attention should be paid, in the open before ObjectContainer, the method must be set to true. 8 display a list of the revised test of the right stack.

A list of 8. Settings for true cascading behavior

                
@Test
public void testWorkingDependentUpdate()
{
    // the cascadeOnUpdate() call must be done while the ObjectContainer 
    // isn't open, so close() it, setCascadeOnUpdate, then open() it again
    db.close();
    Db4o.configure().objectClass(Person.class).cascadeOnUpdate(true);
    db = Db4o.openFile("persons.data");

    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
           
    Person ben = maleGalbraiths.get(0);
    assertTrue(ben.getSpouse().getAge() == 29);
        
    // Happy Birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();
        
    // Close the ObjectContainer, then re-open it
    db.close();
        
    db = Db4o.openFile("persons.data");

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}


Not only can update the settings for the cascading behavior can be retrieved (the creation of value for the "unlimited" activation depth) and set up cascading delete behavior - this is my latest object Person pondering the last application.





Delete the structure of the object

Deleted from the database to retrieve and update objects and objects like this: By default, the deletion of an object does not delete it the object of reference. Generally speaking, this is ideal behavior. 9 such as the list below:

The list 9. To remove the structure of the object

                
@Test
public void simpleDeletion()
{
  Person ben = (Person)db.get(new Person("Ben", "Galbraith", null, 0, null)).next();
  db.delete(ben);
        
  Person jess = (Person)db.get(new Person("Jessica", "Galbraith", null, 0, null)).next();
  assertNotNull(jess);
}


However, some time to delete the object in the hope that the deletion of a mandatory target of the quote. Activated and updated with the same type can be triggered by calling Configuration this behavior. Such as a list of 10 follows:

A list of 10. Configuration.setCascadeOnDelete ()

                
@Test
public void cascadingDeletion()
{
    // the cascadeOnUpdate() call must be done while the ObjectContainer 
    // isn't open, so close() it, setCascadeOnUpdate, then open() it again
    db.close();
    Db4o.configure().objectClass(Person.class).cascadeOnDelete(true);
    db = Db4o.openFile("persons.data");

    Person ben = 
        (Person)db.get(new Person("Ben", "Galbraith", null, 0, null)).next();
    db.delete(ben);
        
    ObjectSet<Person> results = 
        db.get(new Person("Jessica", "Galbraith", null, 0, null));
    assertFalse(results.hasNext());
}


Implementation of the operation to be careful, because it means that the other refers to the object being to eliminate the target stack will have a null reference - db4o object database to be invoked to prevent the deletion of references to the use of object coherence has little effect here . (To quote a general need for consistency is db4o features, it is said the development team is considering a version in the future to add this feature. Db4o for use for the developers, the key is to at least one accident does not violate the principle of achieving and even some of the time, even in the relational database, the consistency of the rules to break is actually an ideal practice.)







Concluding remarks

This is a watershed in the series of articles: Prior to this, all the examples I use are based on very simple objects, from the application point of view, these cases are not reality, its main role is to make you understand OODBMS, instead of being stored the object. Understanding OODBMS such as db4o is how to store the relevant object by reference, which is a more complicated matter. Fortunately, once you've mastered these acts (through the interpretation and understanding), you need to do is just started to adjust the code to achieve these practices.

In this article, you see some basic examples of the complexity of the code by adjusting the db4o object model to achieve. Learning how to structure the implementation of some simple object CRUD operations, at the same time, it is inevitable to see a number of problems and solutions.

In fact, the current structure of the object is still relatively simple example, only between the object by direct reference to the relationship. Many couples are aware, some time after the marriage, the children will appear. The next article in this series, I will continue to explore the structure of db4o in the creation and operation of the object, take a look at after the introduction of a number of sub-objects, ben and what will happen jess object.
  • del.icio.us
  • StumbleUpon
  • Digg
  • TwitThis
  • Mixx
  • Technorati
  • Facebook
  • NewsVine
  • Reddit
  • Google
  • LinkedIn
  • YahooMyWeb

Related Posts of Java developer-oriented guide to db4o: Part 4: Beyond Simple Object

  • hibernate in the get method and the difference between load method

    hibernate in the get method and the load method of the fundamental difference is: If you use the load method, hibernate consider the corresponding object id (database records) are in the database must exist, so it can be assured that the use, it can be as

  • hibernate brief introduction

    1: hibernate, what are? 1: hibernate is a JDBC package is responsible for object persistence, in the middle layer, in the application and database has played a role as a bridge between a mapping tool. Second: Why is the use of hibernate? 1: the use of hib

  • Depth understanding of the eval function in javascript

    http://wanyij.blog.51cto.com/46570/43794 In this paper, the discovery of an appropriate title is not so easy, huh, huh, so in this note under the first two purposes of this article: (1) introduction of the eval function in javascript usage (2) how to func

  • hibernate Technical Study Notes (first)

    Introduction: Model does not match (impedance mismatch) java object-oriented language, object model, its key concepts are: inheritance, association, polymorphism, etc.; database is the relational model, its key concepts are: tables, primary keys, for ...

  • Javascript Object Model

    Javascript Object Model

  • Hibernate II Study Notes

    11. Many-to-many Of many that can be converted to two one-to-many <set name="students" table="teacher_student"> <key column="techer_id"/> <many-to-many column="student_id"/> </set> many-to-many data only from one end of the mainten

  • FLEX: integrating Spring + Hibernate

    Before a friend also wanted to study development of FLEX. Asked me to help him to be a small sample. Spent a weekend time, to integrate a sampleproject. Client: FLEX Server: Spring2.5 + Hibernate3.2 + Hibernate-annotations3.3.1 + MySQL5 FDS: BlazeDS3 IDE:

  • JAVA interview questions

    JAVA interview questions 1, object-oriented features of what has 1. Abstract 2. Inheritance 3. Packaging 4. Polymorphisms 2, String data types are the most basic right? Basic data types include byte, int, char, long, float, double, boolean and short. java

  • Based on JDBC, JPA Annotation achieve simple CRUD Generic Dao

    The origin of ideas are pretty long history of reasons: [Use iBATIS history] The use of iBATIS has been a long time, the system is to use the CRUD template tool to generate the code, although there are tools to generate, but looked at a lot of CRUD the Sq

blog comments powered by Disqus
Recent
Recent Entries
Tag Cloud
Random Entries