Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<com:TContent ID="body">
2
<!-- $Id $ -->
3
 
4
<h1 id="140062">Data Mapper</h1>
5
<com:SinceVersion Version="3.1a" />
6
<p id="700505" class="block-content">Data Mappers moves data between objects and a database while keeping them
7
    independent of each other and the mapper itself. If you started with
8
    <a href="?page=Database.ActiveRecord">Active Records</a>, you may eventually
9
     faced with more complex business
10
    objects as your project progresses. When you build an object model with a
11
     lot of business logic it's valuable to use these mechanisms to better organize
12
     the data and the behavior that goes with it. Doing so leads to variant schemas;
13
     that is, the object schema and the relational schema don't match up.
14
</p>
15
 
16
<p id="700506" class="block-content">The Data Mapper separates the in-memory objects from the database. Its responsibility
17
    is to transfer data between the two and also to isolate them from each other.
18
    With Data Mapper the in-memory objects needn't know even that there's a database
19
    present; they need no SQL interface code, and certainly no knowledge of the
20
     database schema. (The database schema is always ignorant of the objects that use it.)
21
</p>
22
 
23
<h2 id="140063">When to Use It</h2>
24
<p id="700507" class="block-content">The primary occasion for using Data Mapper is when you want the database schema
25
     and the object model to evolve independently. Data Mapper's primary benefit is
26
     that when working on the business (or domain) objects you can ignore the database, both in
27
     design and in the build and testing process. The domain objects have no idea
28
     what the database structure is, because all the correspondence is done by the mappers.
29
</p>
30
 
31
<p id="700508" class="block-content">This helps you in the code because you can understand and work with the domain objects
32
    without having to understand how they're stored in the database. You can modify the
33
    business models or the database without having to alter either. With complicated
34
    mappings, particularly those involving <b>existing databases</b>, this is very valuable.
35
</p>
36
 
37
<p id="700509" class="block-content">The price, of course, is the extra layer that you don't get with
38
    <a href="?page=Database.ActiveRecord">Active Record</a>,
39
    so the test for using these patterns is the complexity of the business logic.
40
    If you have fairly simple business logic, an <a href="?page=Database.ActiveRecord">Active Record</a>
41
    will probably work.
42
    For more complicated logic a Data Mapper may be more suitable.
43
</p>
44
 
45
<h2 id="140064">SqlMap Data Mapper</h2>
46
<p id="700510" class="block-content">The SqlMap DataMapper framework makes it easier to use a database with a PHP application.
47
    SqlMap DataMapper couples objects with stored procedures or SQL statements using
48
    a XML descriptor. Simplicity is the biggest advantage of the SqlMap DataMapper over
49
    object relational mapping tools. To use SqlMap DataMapper you rely on your own objects,
50
    XML, and SQL. There is little to learn that you don't already know.
51
    With SqlMap DataMapper you have the full power of both SQL and stored procedures at
52
    your fingertip
53
</p>
54
 
55
<p id="700511" class="block-content">
56
    <img src=<%~ diagram.png %> alt="SqlMap Data Mapper Overview" id="fig:sqlmap.png" class="figure"/>
57
 
58
    Here's a high level description of the work flow illustrated in the figure above.
59
    Provide a parameter, either as an object or a primitive type. The parameter can be
60
     used to set runtime values in your SQL statement or stored procedure. If a runtime value
61
    is not needed, the parameter can be omitted.
62
</p>
63
<p id="700512" class="block-content">Execute the mapping by passing the parameter and the name you gave the statement or
64
    procedure in your XML descriptor. This step is where the magic happens. The framework
65
     will prepare the SQL statement or stored procedure, set any runtime values using your
66
    parameter, execute the procedure or statement, and return the result.
67
</p>
68
 
69
<p id="700513" class="block-content">In the case of an update, the number of rows affected is returned. In the case of a
70
     query, a single object, or a collection of objects is returned. Like the parameter,
71
    the result object, or collection of objects, can be a plain-old object or a primitive PHP type.
72
</p>
73
 
74
<h2 id="140065">Setting up a database connection and initializing the SqlMap</h2>
75
<p id="700514" class="block-content">
76
    A database connection for SqlMap can be set as follows.
77
    See <a href="?page=Database.DAO">Establishing Database Connection</a> for
78
    futher details regarding creation of database connection in general.
79
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700166">
80
//create a connection and give it to the SqlMap manager.
81
$dsn = 'pgsql:host=localhost;dbname=test'; //Postgres SQL
82
$conn = new TDbConnection($dsn, 'dbuser','dbpass');
83
$manager = new TSqlMapManager($conn);
84
$manager->configureXml('my-sqlmap.xml');
85
$sqlmap = $manager->getSqlMapGateway();
86
</com:TTextHighlighter>
87
</p>
88
 
89
<p id="700515" class="block-content">
90
    The <tt>TSqlMapManager</tt> is responsible for setting up the database connection
91
    and configuring the SqlMap with given XML file(s). The <tt>configureXml()</tt>
92
    method accepts a string that points to a SqlMap XML configuration file. Once
93
    configured, call the <tt>getSqlMapGateway()</tt> method to obtain an instance
94
    of the SqlMap gateway interface (use this object to insert/delete/find records).
95
</p>
96
 
97
<p id="700516" class="block-content">
98
    SqlMap database connection can also be configured using a <tt>&lt;module&gt;</tt>
99
    tag in the <a href="?page=Configurations.AppConfig">application.xml</a>
100
    or <a href="?page=Configurations.PageConfig">config.xml</a> as follows.
101
<com:TTextHighlighter Language="xml" CssClass="source block-content" id="code_700167">
102
<modules>
103
  <module id="my-sqlmap" class="System.Data.SqlMap.TSqlMapConfig"
104
        EnableCache="true" ConfigFile="my-sqlmap.xml" >
105
    <database ConnectionString="pgsql:host=localhost;dbname=test"
106
        Username="dbuser" Password="dbpass" />
107
  </module>
108
</modules>
109
</com:TTextHighlighter>
110
</p>
111
 
112
<p id="700517" class="block-content">
113
    The <tt>ConfigFile</tt> attribute should point to a SqlMap configuration file
114
    (to be detailed later) either using absolute path, relative path or the
115
    Prado's namespace dot notation path (must omit the ".xml" extension).
116
 
117
    <div class="tip"><b class="note">Tip:</b>
118
        The <tt>EnableCache</tt> attribute when set to "true" will cache the
119
        parsed configuration. You must clear or disable the cache if you
120
        make changes to your configuration file.
121
        A <a href="?page=Advanced.Performance#6402">cache
122
        module</a> must also be defined for the cache to function.
123
    </div>
124
</p>
125
 
126
<p id="700518" class="block-content">To obtain the SqlMap gateway interface from the &lt;module&gt; configuration, simply
127
    do, for example,
128
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700168">
129
class MyPage extends TPage
130
{
131
    public function onLoad($param)
132
    {
133
        parent::onLoad($param);
134
        $sqlmap = $this->Application->Modules['my-sqlmap']->Client;
135
        $sqlmap->queryForObject(...); //query for some object
136
    }
137
}
138
</com:TTextHighlighter>
139
</p>
140
 
141
<h2 id="140066">A quick example</h2>
142
<p id="700519" class="block-content">Let us
143
    consider the following "users" table that contains two columns named "username" and "email",
144
    where "username" is also the primary key.
145
<com:TTextHighlighter Language="sql" CssClass="source block-content" id="code_700169">
146
CREATE TABLE users
147
(
148
    username VARCHAR( 20 ) NOT NULL ,
149
    email VARCHAR( 200 ) ,
150
    PRIMARY KEY ( username )
151
);
152
</com:TTextHighlighter>
153
</p>
154
<p id="700520" class="block-content">Next we define our plain <tt>User</tt> class as follows. Notice that
155
    the <tt>User</tt> is very simple.
156
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700170">
157
class User
158
{
159
    public $username;
160
    public $email;
161
}
162
</com:TTextHighlighter>
163
</p>
164
</p>
165
 
166
<p id="700521" class="block-content">Next, we need to define a SqlMap XMl configuration file, lets name
167
    the file as <tt>my-sqlmap.xml</tt>
168
<com:TTextHighlighter Language="xml" CssClass="source block-content" id="code_700171">
169
<?xml version="1.0" encoding="utf-8" ?>
170
<sqlMapConfig>
171
    <select id="SelectUsers" resultClass="User">
172
        SELECT username, email FROM users
173
    </select>
174
</sqlMapConfig>
175
</com:TTextHighlighter>
176
</p>
177
<p id="700522" class="block-content">The &lt;select&gt; tag returns defines an SQL statement. The <tt>id</tt>
178
    attribute will be used as the identifier for the query. The <tt>resultClass</tt>
179
    attribute value is the name of the class the the objects to be returned.
180
    We can now query the objects as follows:
181
 
182
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700172">
183
//assume that $sqlmap is an TSqlMapGateway instance
184
$userList = $sqlmap->queryForList("SelectUsers");
185
 
186
//Or just one, if that's all you need:
187
$user = $sqlmap->queryForObject("SelectUsers");
188
</com:TTextHighlighter>
189
</p>
190
 
191
<p id="700523" class="block-content">The above example shows demonstrates only a fraction of the capabilities
192
    of the SqlMap Data Mapper. Further details can be found in the
193
    <a href="http://www.pradosoft.com/demo/sqlamp/">SqlMap Manual</a>.
194
</p>
195
 
196
<h2 id="140067">Combining SqlMap with Active Records</h2>
197
<p id="700524" class="block-content">The above example may seem trival and it also seems that there is
198
    alot work just to retrieve some data. However, notice that the <tt>User</tt>
199
    class is totally unware of been stored in the database, and the database is
200
    unware of the <tt>User</tt> class.
201
</p>
202
<p id="700525" class="block-content">
203
    One of advantages of SqlMap is the
204
    ability to map complex object relationship, collections from an existing
205
    database. On the other hand, <a href="?page=Database.ActiveRecord">Active Record</a>
206
    provide a very simple way
207
    to interact with the underlying database but unable to do more complicated
208
    relationship or collections. A good compromise is to use SqlMap to retrieve
209
    complicated relationships and collections as Active Record objects and then using
210
    these Active Records to do the updates, inserts and deletes.
211
</p>
212
<p id="700526" class="block-content">Continuing with the previous example, we change the definition of the
213
    <tt>User</tt> class to become an Active Record.
214
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700173">
215
class UserRecord extends TActiveRecord
216
{
217
	const TABLE='users'; //table name
218
 
219
    public $username; //the column named "username" in the "users" table
220
    public $email;
221
 
222
    /**
223
     * @return TActiveRecord active record finder instance
224
     */
225
    public static function finder($className=__CLASS__)
226
    {
227
        return parent::finder($className);
228
    }
229
}
230
</com:TTextHighlighter>
231
</p>
232
 
233
<p id="700527" class="block-content">We also need to change the definition of the SqlMap XML configuration. We
234
    just need to change the value of <tt>resultClass</tt> attribute to <tt>UserRecord</tt>.
235
<com:TTextHighlighter Language="xml" CssClass="source block-content" id="code_700174">
236
<?xml version="1.0" encoding="utf-8" ?>
237
<sqlMapConfig>
238
    <select id="SelectUsers" resultClass="UserRecord">
239
        SELECT username, email FROM users
240
    </select>
241
</sqlMapConfig>
242
</com:TTextHighlighter>
243
</p>
244
 
245
 
246
<p id="700528" class="block-content">The PHP code for retrieving the users remains the same, but SqlMap
247
    returns Active Records instead, and we can take advantage of the Active Record methods.
248
 
249
<com:TTextHighlighter Language="php" CssClass="source block-content" id="code_700175">
250
//assume that $sqlmap is an TSqlMapGateway instance
251
$user = $sqlmap->queryForObject("SelectUsers");
252
 
253
$user->email = 'test@example.com'; //change data
254
$user->save(); //save it using Active Record
255
</com:TTextHighlighter>
256
</p>
257
 
258
<h2 id="140068">References</h2>
259
<ul id="u1" class="block-content">
260
    <li>Fowler et. al. <i>Patterns of Enterprise Application Architecture</i>,
261
    Addison Wesley, 2002.</li>
262
    <li>iBatis Team. <i>iBatis Data Mapper</i>,
263
    <a href="http://ibatis.apache.org">http://ibatis.apache.org</a>.</li>
264
</ul>
265
 
266
<div class="last-modified">$Id: SqlMap.page 2136 2007-08-20 12:09:02Z xue $</div></com:TContent>