Update wikipage Dealing with references. (Signed-off-by:jocelyn).

git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1460 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
eiffel-org
2015-11-24 09:10:05 +00:00
parent 7ee4a92b0c
commit c2d80a5cda

View File

@@ -1,150 +1,150 @@
[[Property:title|Dealing with references]] [[Property:title|Dealing with references]]
[[Property:weight|-6]] [[Property:weight|-6]]
[[Property:uuid|ebf8e495-8180-bad2-f063-54fb949298e0]] [[Property:uuid|1190C592-50E0-4834-9D60-E1E357921335]]
In ABEL, a basic type is an object of type <e>STRING</e>, <e>BOOLEAN</e>, <e>CHARACTER</e> or any numeric class like <e>REAL</e> or <e>INTEGER</e>. In ABEL, a basic type is an object of type <e>STRING</e>, <e>BOOLEAN</e>, <e>CHARACTER</e> or any numeric class like <e>REAL</e> or <e>INTEGER</e>.
The <e>PERSON</e> class only has attributes of a basic type. The <e>PERSON</e> class only has attributes of a basic type.
However, an object can contain references to other objects. ABEL is able to handle these references by storing and reconstructing the whole object graph However, an object can contain references to other objects. ABEL is able to handle these references by storing and reconstructing the whole object graph
(an object graph is roughly defined as all the objects that can be reached by recursively following all references, starting at some root object). (an object graph is roughly defined as all the objects that can be reached by recursively following all references, starting at some root object).
==Inserting objects with references== ==Inserting objects with references==
Let's look at the new class <e>CHILD</e>: Let's look at the new class <e>CHILD</e>:
<code> <code>
class class
CHILD CHILD
create create
make make
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (first, last: STRING) make (first, last: STRING)
-- Create a new child. -- Create a new child.
require require
first_exists: not first.is_empty first_exists: not first.is_empty
last_exists: not last.is_empty last_exists: not last.is_empty
do do
first_name := first first_name := first
last_name := last last_name := last
age := 0 age := 0
ensure ensure
first_name_set: first_name = first first_name_set: first_name = first
last_name_set: last_name = last last_name_set: last_name = last
default_age: age = 0 default_age: age = 0
end end
feature -- Access feature -- Access
first_name: STRING first_name: STRING
-- The child's first name. -- The child's first name.
last_name: STRING last_name: STRING
-- The child's last name. -- The child's last name.
age: INTEGER age: INTEGER
-- The child's age. -- The child's age.
father: detachable CHILD father: detachable CHILD
-- The child's father. -- The child's father.
feature -- Element Change feature -- Element Change
celebrate_birthday celebrate_birthday
-- Increase age by 1. -- Increase age by 1.
do do
age := age + 1 age := age + 1
ensure ensure
age_incremented_by_one: age = old age + 1 age_incremented_by_one: age = old age + 1
end end
set_father (a_father: CHILD) set_father (a_father: CHILD)
-- Set a father for the child. -- Set a father for the child.
do do
father := a_father father := a_father
ensure ensure
father_set: father = a_father father_set: father = a_father
end end
invariant invariant
age_non_negative: age >= 0 age_non_negative: age >= 0
first_name_exists: not first_name.is_empty first_name_exists: not first_name.is_empty
last_name_exists: not last_name.is_empty last_name_exists: not last_name.is_empty
end end
</code> </code>
This adds in some complexity: This adds some complexity:
Instead of having a single object, ABEL has to insert a <e>CHILD</e>'s mother and father as well, and it has to repeat this procedure if their parent attribute is also attached. Instead of having a single object, ABEL has to insert a <e>CHILD</e>'s mother and father as well, and it has to repeat this procedure if their parent attribute is also attached.
The good news are that the examples above will work exactly the same. The good news is that the examples above will work exactly the same.
However, there are some additional caveats to take into consideration. However, there are some additional caveats to take into consideration.
Let's consider a simple example with <e>CHILD</e> objects ''Baby Doe'', ''John Doe'' and ''Grandpa Doe''. Let's consider a simple example with <e>CHILD</e> objects ''Baby Doe'', ''John Doe'' and ''Grandpa Doe''.
From the name of the object instances you can already guess what the object graph looks like: From the name of the object instances you can already guess what the object graph looks like:
[[Image: Child object graph | center | 700px]] [[Image:Child object graph | center | 700px]]
Now if you insert ''Baby Doe'', ABEL will by default follow all references and insert every single object along the object graph, which means that ''John Doe'' and ''Grandpa Doe'' will be inserted as well. Now if you insert ''Baby Doe'', ABEL will by default follow all references and insert every single object along the object graph, which means that ''John Doe'' and ''Grandpa Doe'' will be inserted as well.
This is usually the desired behavior, as objects are stored completely that way, but it also has some side effects we need to be aware of: This is usually the desired behavior, as objects are stored completely that way, but it also has some side effects we need to be aware of:
* Assume an insert of ''Baby Doe'' has happened to an empty database. If you now query the database for <e>CHILD</e> objects, it will return exactly the same object graph as above, but the query result will actually have three items, as the object graph consists of three single <e>CHILD</e> objects. * Assume an insert of ''Baby Doe'' has happened to an empty database. If you now query the database for <e>CHILD</e> objects, it will return exactly the same object graph as above, but the query result will actually have three items as the object graph consists of three single <e>CHILD</e> objects.
* The insert of ''John Doe'' and ''Grandpa Doe'', after inserting ''Baby Doe'', is internally changed to an update operation because both objects are already in the database. This might result in some undesired overhead which can be avoided if you know the object structure. * The insert of ''John Doe'' and ''Grandpa Doe'', after inserting ''Baby Doe'', is internally changed to an update operation because both objects are already in the database. This might result in some undesired overhead which can be avoided if you know the object structure.
In our main tutorial class <e>START</e> we have the following two features that show how to deal with object graphs. In our main tutorial class <e>START</e> we have the following two features that show how to deal with object graphs.
You will notice it is very similar to the corresponding routines for the flat <e>PERSON</e> objects. You will notice it is very similar to the corresponding routines for the flat <e>PERSON</e> objects.
<code> <code>
insert_children insert_children
-- Populate the repository with some children objects. -- Populate the repository with some children objects.
local local
c1, c2, c3: CHILD c1, c2, c3: CHILD
transaction: PS_TRANSACTION transaction: PS_TRANSACTION
do do
-- Create the object graph. -- Create the object graph.
create c1.make ("Baby", "Doe") create c1.make ("Baby", "Doe")
create c2.make ("John", "Doe") create c2.make ("John", "Doe")
create c3.make ("Grandpa", "Doe") create c3.make ("Grandpa", "Doe")
c1.set_father (c2) c1.set_father (c2)
c2.set_father (c3) c2.set_father (c3)
print ("Insert 3 children in the database.%N") print ("Insert 3 children in the database.%N")
transaction := repository.new_transaction transaction := repository.new_transaction
-- It is sufficient to just insert "Baby Joe", -- It is sufficient to just insert "Baby Joe",
-- as the other CHILD objects are (transitively) -- as the other CHILD objects are (transitively)
-- referenced and thus inserted automatically. -- referenced and thus inserted automatically.
if not transaction.has_error then if not transaction.has_error then
transaction.insert (c1) transaction.insert (c1)
end end
if not transaction.has_error then if not transaction.has_error then
transaction.commit transaction.commit
end end
if transaction.has_error then if transaction.has_error then
print ("An error occurred during insert!%N") print ("An error occurred during insert!%N")
end end
end end
print_children print_children
-- Print all children in the repository -- Print all children in the repository
local local
query: PS_QUERY[CHILD] query: PS_QUERY[CHILD]
do do
create query.make create query.make
repository.execute_query (query) repository.execute_query (query)
-- The result will also contain -- The result will also contain
-- all referenced CHILD objects. -- all referenced CHILD objects.
across across
query as person_cursor query as person_cursor
loop loop
print (person_cursor.item) print (person_cursor.item)
end end
query.close query.close
end end
</code> </code>
==Going deeper in the Object Graph== ==Going deeper in the Object Graph==
ABEL has no limits regarding the depth of an object graph, and it will detect and handle reference cycles correctly. ABEL has no limits regarding the depth of an object graph, and it will detect and handle reference cycles correctly.
You are welcome to test ABEL's capability with very complex objects, however please keep in mind that this may impact performance significantly. You are welcome to test ABEL's capability with very complex objects, however, please keep in mind that this may impact performance significantly.