diff options
author | wei <> | 2006-04-14 06:22:09 +0000 |
---|---|---|
committer | wei <> | 2006-04-14 06:22:09 +0000 |
commit | 3d3f8d3832921f99daf8ce1953304763c2e76c62 (patch) | |
tree | e1b0a9bc3a13fccd253770fb452ac96cc6315121 /docs/sqlmap/latex | |
parent | 373d8acc503b94ea09823f49e2ab5e395eccc584 (diff) |
Importing SQLMap + sample + docs.
Diffstat (limited to 'docs/sqlmap/latex')
-rw-r--r-- | docs/sqlmap/latex/ch1.tex | 43 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch2.tex | 151 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch3.tex | 714 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch4.tex | 306 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch5.tex | 941 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch6.tex | 119 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch7.tex | 3 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch8.tex | 413 | ||||
-rw-r--r-- | docs/sqlmap/latex/ch9.tex | 302 | ||||
-rw-r--r-- | docs/sqlmap/latex/diagram.pdf | bin | 0 -> 521561 bytes | |||
-rw-r--r-- | docs/sqlmap/latex/example1.png | bin | 0 -> 236887 bytes | |||
-rw-r--r-- | docs/sqlmap/latex/grid1.png | bin | 0 -> 275250 bytes | |||
-rw-r--r-- | docs/sqlmap/latex/grid2.png | bin | 0 -> 218210 bytes | |||
-rw-r--r-- | docs/sqlmap/latex/sqlmap.tex | 143 | ||||
-rw-r--r-- | docs/sqlmap/latex/sqlmap_tut.tex | 96 | ||||
-rw-r--r-- | docs/sqlmap/latex/tut1.tex | 257 | ||||
-rw-r--r-- | docs/sqlmap/latex/tut2.tex | 128 | ||||
-rw-r--r-- | docs/sqlmap/latex/tut3.tex | 227 |
18 files changed, 3843 insertions, 0 deletions
diff --git a/docs/sqlmap/latex/ch1.tex b/docs/sqlmap/latex/ch1.tex new file mode 100644 index 00000000..405256ef --- /dev/null +++ b/docs/sqlmap/latex/ch1.tex @@ -0,0 +1,43 @@ +\chapter{Introduction}
+
+\section{Overview}
+
+The SQLMap DataMapper framework makes it easier to use a database with a PHP
+application. SQLMap DataMapper couples objects with stored procedures or SQL
+statements using a XML descriptor. Simplicity is the biggest advantage of the
+SQLMap DataMapper over object relational mapping tools. To use SQLMap
+DataMapper you rely on your own objects, XML, and SQL. There is little to
+learn that you don't already know. With SQLMap DataMapper you have the full
+power of both SQL and stored procedures at your fingertips.
+
+The SQLMap for PHP is based on iBATIS.NET - DataMapper Application Framework
+from http://ibatis.apache.org/.The PHP version support most of the features
+found in iBATIS.NET exception the following:
+
+\begin{itemize}
+ \item Dynamic SQL.
+ \item Distributed Transactions.
+\end{itemize}
+
+\section{What's covered here}
+
+This Guide covers the PHP implementations of SQLMap DataMapper. The Java and
+.NET implementation offers the same services with some changes in the API.
+
+Since SQLMap relies on an XML descriptor to create the mappings, much of the
+material applies to both implementations.
+
+For installation instructions, see the section called the SQLMap PHP Developer
+Guide.
+
+A Tutorial is also available. We recommend reviewing the Tutorial for your
+platform before reading this Guide.
+
+\section{Support}
+
+Add Forum and Trac.
+
+\section{Disclaimer}
+SQLMap MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE INFORMATION IN THIS
+DOCUMENT. The names of actual companies and products mentioned herein may be
+the trademarks of their respective owners.
diff --git a/docs/sqlmap/latex/ch2.tex b/docs/sqlmap/latex/ch2.tex new file mode 100644 index 00000000..da135e9c --- /dev/null +++ b/docs/sqlmap/latex/ch2.tex @@ -0,0 +1,151 @@ +\chapter{The Big Picture}
+\section{Introduction}
+SQLMap is a simple but complete framework that makes it easy for you to map
+your objects to your SQL statements or stored procedures. The goal of the
+SQLMap framework is to obtain 80\% of data access functionality using only
+20\% of the code.
+
+\section{What does it do?}
+Developers often create maps between objects within an application. One
+definition of a Mapper is an ``object that sets up communication between two
+independent objects.'' A Data Mapper is a ``layer of mappers that moves data
+between objects and a database while keeping them independent of each other
+and the mapper itself.'' [Patterns of Enterprise Architecture, ISBN
+0-321-12742-0].
+
+You provide the database and the objects; SQLMap provides the mapping layer
+that goes between the two.
+
+\section{How does it work?}
+
+Your programming platform already provides a capable library for accessing
+databases, whether through SQL statements or stored procedures. But developers
+find several things are still hard to do well when using ``stock'' PHP
+function including:
+
+Separating SQL code from programming code Passing input parameters to the
+library classes and extracting the output Separating data access classes from
+business logic classes Caching often-used data until it changes Managing
+transactions and many more -- by using XML documents to create a mapping
+between a plain-old object and a SQL statement or a stored procedure. The
+``plain-old object'' can be any PHP object.
+
+\begin{mybox}{Tip:}
+The object does not need to be part of a special object hierarchy or implement
+a special interface. (Which is why we call them ``plain-old'' objects.)
+Whatever you are already using should work just fine.
+\end{mybox}
+
+\begin{figure}[!h]
+ \centering
+ \includegraphics[width=0.65\textwidth]{diagram}
+ \caption{SQLMap DataMapper work flow}
+ \label{fig:diagram}
+\end{figure}
+
+Here's a high level description of the work flow diagrammed by
+Figure~\ref{fig:diagram}: Provide a parameter, either as an object or a
+primitive type. The parameter can be used to set runtime values in your SQL
+statement or stored procedure. If a runtime value is not needed, the parameter
+can be omitted.
+
+Execute the mapping by passing the parameter and the name you gave the
+statement or procedure in your XML descriptor. This step is where the magic
+happens. The framework will prepare the SQL statement or stored procedure, set
+any runtime values using your parameter, execute the procedure or statement,
+and return the result.
+
+In the case of an update, the number of rows affected is returned. In the case
+of a query, a single object, or a collection of objects is returned. Like the
+parameter, the result object, or collection of objects, can be a plain-old
+object or a primitive type.
+
+So, what does all this look like in your source code? Here's how you might
+code the insert of a ``lineItem'' object into your database.
+
+\begin{verbatim}
+TMapper::instance()->insert("InsertLineItem", $lineItem);
+\end{verbatim}
+
+If your database is generating the primary keys, the generated key can be
+returned from the same method call, like this:
+
+\begin{verbatim}
+$myKey = TMapper::instance()->insert("InsertLineItem", $lineItem);
+\end{verbatim}
+
+Example~\ref{example:2.1} shows an XML descriptor for ``InsertLineItem''.
+\begin{example}\label{example:2.1}
+The ``InsertLineItem'' descriptor
+\begin{verbatim}
+<insert id="InsertLineItem" parameterClass="LineItem">
+ INSERT INTO [LinesItem]
+ (Order_Id, LineItem_LineNum, Item_Id, LineItem_Quantity, LineItem_UnitPrice)
+ VALUES
+ (#Order.Id#, #LineNumber#, #Item.Id#, #Quantity#, #Item.ListPrice#)
+ <selectKey type="post" resultClass="int" property="Id" >
+ select @@IDENTITY as value
+ </selectKey>
+</insert>
+\end{verbatim}
+\end{example}
+
+The \tt{<selectKey>} stanza returns an auto-generated key from a SQL Server
+database (for example). If you need to select multiple rows, SQLMap can return
+a list of objects, each mapped to a row in the result set:
+\begin{verbatim}
+$productList = Mapper::instance()->queryForList("selectProduct",$categoryKey);
+\end{verbatim}
+Or just one, if that's all you need:
+\begin{verbatim}
+$product = Mapper::instance()->queryForObject("selectProduct",$categoryKey);
+\end{verbatim}
+
+Of course, there's more, but this is SQLMap from 10,000 meters. (For a longer,
+gentler introduction, see the Tutorial.) Section~\ref{section:3} describes the
+Data Map definition files -- where the statement for ``InsertLineItem'' would
+be defined. The Developers Guide for PHP (Section~\ref{section:4}) describes
+the "bootstrap" configuration file that exposes SQLMap to your application.
+
+\section{Is SQLMap the best choice for my project?}
+SQLMap is a Data Mapping tool. Its role is to map the columns of a database
+query (including a stored procedure) to the properties of an object. If your
+application is based on business objects (including array or lists of
+objects), then SQLMap can be a good choice. SQLMap is an even better choice
+when your application is layered, so that that the business layer is distinct
+from the user-interface layer.
+
+Under these circumstances, another good choice would be an Object/Relational
+Mapping tool (OR/M tool), like [...]. Other products in this category are
+[...] and [...] . An OR/M tool generates all or most of the SQL for you,
+either beforehand or at runtime. These products are called OR/M tools because
+they try to map an object graph to a relational schema.
+
+SQLMap is not an OR/M tool. SQLMap helps you map objects to stored procedures
+or SQL statements. The underlying schema is irrelevant. An OR/M tool is great
+if you can map your objects to tables. But they are not so great if your
+objects are stored as a relational view rather than as a table. If you can
+write a statement or procedure that exposes the columns for your object,
+regardless of how they are stored, SQLMap can do the rest.
+
+So, how do you decide whether to OR/M or to DataMap? As always, the best
+advice is to implement a representative part of your project using either
+approach, and then decide. But, in general, OR/M is a good thing when you
+\begin{itemize}
+ \item Have complete control over your database implementation.
+ \item Do not have a Database Administrator or SQL guru on the team.
+ \item Need to model the problem domain outside the database as an object graph.
+\end{itemize}
+Likewise, the best time to use a Data Mapper, like SQLMap, is when:
+\begin{itemize}
+ \item You do not have complete control over the database implementation, or want to
+continue to access a legacy database as it is being refactored.
+ \item You have database administrators or SQL gurus on the team.
+ \item The database is being used to model the problem domain, and the application's
+primary role is to help the client use the database model.
+\end{itemize}
+
+In the end, you have to decide what's best for your project. If a OR/M tool
+works better for you, that's great! If your next project has different needs,
+then we hope you give SQLMap another look. If SQLMap works for you now:
+Excellent!
diff --git a/docs/sqlmap/latex/ch3.tex b/docs/sqlmap/latex/ch3.tex new file mode 100644 index 00000000..79b2c42a --- /dev/null +++ b/docs/sqlmap/latex/ch3.tex @@ -0,0 +1,714 @@ +\chapter{Working with Data Maps}\label{section:3}
+\section{Introduction}
+
+If you want to know how to configure and install SQLMap, see the Developer
+Guide section~\ref{section:4} . But if you want to know how SQLMap really
+works, continue from here.
+
+The Data Map definition file is where the interesting stuff happens. Here, you
+define how your application interacts with your database. As mentioned, the
+Data Map definition is an XML descriptor file. By using a service routine
+provided by SQLMap, the XML descriptors are rendered into a client object (or
+Mapper). To access your Data Maps, your application calls the client object
+and passes in the name of the statement you need.
+
+The real work of using SQLMap is not so much in the application code, but in
+the XML descriptors that SQLMap renders. Instead of monkeying with application
+source code, you monkey with XML descriptors instead. The benefit is that the
+XML descriptors are much better suited to the task of mapping your object
+properties to database entities. At least, that's our own experience with our
+own applications. Of course, your mileage may vary.
+
+\section{What's in a Data Map definition file, anyway?}
+
+If you read the Tutorial, you've already seen some simple Data Map examples,
+like the one shown in Example~\ref{example:2.1}.
+
+\begin{example}\label{example:3.1}
+ A simple Data Map (PHP)
+ \begin{verbatim}
+<?xml version="1.0" encoding="UTF-8" ?>
+ <sqlMap namespace="LineItem">
+ <insert id="InsertLineItem" parameterClass="LineItem">
+ INSERT INTO [LinesItem]
+ (Order_Id, LineItem_LineNum, Item_Id, LineItem_Quantity, LineItem_UnitPrice)
+ VALUES
+ (#Order.Id#, #LineNumber#, #Item.Id#, #Quantity#, #Item.ListPrice#)
+ </insert>
+</sqlMap>
+ \end{verbatim}
+\end{example}
+This map takes some properties from a \tt{LineItem} instance and merges the
+values into the SQL statement. The value-add is that our SQL in separated from
+our program code, and we can pass our \tt{LineItem} instance directly to a
+library method:
+\begin{verbatim}
+TMapper::instance()->insert("InsertLineItem",$lineItem);
+\end{verbatim}
+No fuss, no muss. Likewise, see Example\ref{example:3.2} for a simple select
+statement.
+
+\begin{mybox}{Info:}
+\textbf{A Quick Glance at Inline Parameters}
+
+Say we have a mapped statement element that looks like this:
+\begin{verbatim}
+ <statement id="InsertProduct">
+ insert into Products (Product_Id, Product_Description)
+ values (#Id#, #Description#);
+</statement>
+\end{verbatim}
+The inline parameters here are \tt{\#Id\#} and \tt{\#Description\#}. Let's
+also say that we have an object with the properties \tt{Id} and
+\tt{Description}. If we set the object properties to $5$ and ``dog'',
+respectively, and passed the object to the mapped statement, we'd end up with
+a runtime query that looked like this:
+\begin{verbatim}
+insert into Products (Product_Id, Product_Description) values (5, 'dog');
+\end{verbatim}
+For more about inline parameters, see Chapter~\ref{section:3.4}.
+\end{mybox}
+
+But, what if you wanted some ice cream with that pie? And maybe a cherry on
+top? What if we wanted to cache the result of the select? Or, what if we
+didn't want to use SQL aliasing or named parameters. (Say, because we were
+using pre-existing SQL that we didn't want to touch.)
+Example~\ref{example:3.2} shows a Data Map that specifies a cache, and uses a
+\tt{<parameterMap>} and a \tt{<resultMap>} to keep our SQL pristine.
+
+\begin{example}\label{example:3.2}
+A Data Map definition file with some bells and whistles
+\begin{verbatim}
+<?xml version="1.0" encoding="UTF-8" ?>
+ <sqlMap namespace="Product">
+
+ <cacheModel id="productCache" type="LRU">
+ <flushInterval hours="24"/>
+ <property name="CacheSize" value="1000" />
+ </cacheModel>
+
+ <resultMap id="productResult" class="Product">
+ <result property="Id" column="Product_Id"/>
+ <result property="Description" column="Product_Description"/>
+ </resultMap>
+
+ <select id="GetProduct" parameterMap="productParam" cacheModel="productCache">
+ select * from Products where Product_Id = ?
+ </select>
+
+ <parameterMap id="productParam" class="Product">
+ <parameter property="Id"/>
+ </parameterMap>
+
+</sqlMap>
+\end{verbatim}
+\end{example}
+In Example~\ref{example:3.2}, \tt{<parameterMap>} maps the SQL ``?'' to the
+product \tt{Id} property. The \tt{<resultMap>} maps the columns to our object
+properties. The \tt{<cacheModel>} keeps the result of the last one thousand of
+these queries in active memory for up to 24 hours.
+
+Example~\ref{example:3.2} is longer and more complex than
+Example~\ref{example:3.1}, but considering what you get in return, it seems
+like a fair trade. (A bargain even.)
+
+Many agile developers would start with something like
+Example~\ref{example:3.1} and add features like caching later. If you changed
+the Data Map from Example~\ref{example:3.1} to Example~\ref{example:3.2}, you
+would not have to touch your application source code at all. You can start
+simple and add complexity only when it is needed.
+
+A single Data Map definition file can contain as many Cache Models, Type
+Aliases, Result Maps, Parameter Maps, and Mapped Statements (including stored
+procedures), as you like. Everything is loaded into the same configuration, so
+you can define elements in one Data Map and then use them in another. Use
+discretion and organize the statements and maps appropriately for your
+application by finding some logical way to group them.
+
+\section{Mapped Statements}
+Mapped Statements can hold any SQL statement and can use Parameter Maps and
+Result Maps for input and output. (A stored procedure is a specialized form of
+a statement. See section~\ref{section:3.3.1} and \ref{section:3.3.2} for more
+information.)
+
+If the case is simple, the Mapped Statement can reference the parameter and
+result classes directly. Mapped Statements support caching through reference
+to a Cache Model element. The following example shows the syntax for a
+statement element.
+
+\begin{example}\label{example:3.3}
+Statement element syntax
+\begin{verbatim}
+<statement id="statement.name"
+ [parameterMap="parameterMap.name"]
+ [parameterClass="class.name"]
+ [resultMap="resultMap.name"]
+ [resultClass="class.name"]
+ [listClass="class.name"]
+ [cacheModel="cache.name"]
+>
+
+ select * from Products where Product_Id = [?|#propertyName#]
+ order by [$simpleDynamic$]
+
+</statement>
+\end{verbatim}
+\end{example}
+In Example~\ref{example:3.3}, the [bracketed] parts are optional, and some
+options are mutually exclusive. It is perfectly legal to have a Mapped
+Statement as simple as shown by Example~\ref{example:3.4}.
+
+\begin{example}\label{example:3.4}
+A simplistic Mapped Statement
+\begin{verbatim}
+<statement id="InsertTestProduct" >
+ insert into Products (Product_Id, Product_Description) values (1, "Shih Tzu")
+</statement>
+\end{verbatim}
+\end{example}
+
+Example~\ref{example:3.4} is obviously unlikely, unless you are running a
+test. But it does shows that you can use SQLMap to execute arbitrary SQL
+statements. More likely, you will use the object mapping features with
+Parameter Maps (Chapter~\ref{section:3.4}) and Result Maps
+(Chapter~\ref{section:3.5}) since that's where the magic happens.
+
+\subsection{Statement Types}\label{section:3.3.1}
+The \tt{<statement>} element is a general ``catch all'' element that can be
+used for any type of SQL statement. Generally it is a good idea to use one of
+the more specific statement-type elements. The more specific elements provided
+better error-checking and even more functionality. (For example, the insert
+statement can return a database-generated key.) Table~\ref{table:3.1}
+summarizes the statement-type elements and their supported attributes and
+features. The various attributes used by statement-type elements are covered
+in Section~\ref{section:3.3.4}.
+\begin{table}[!hpt]
+\caption{The six statement-type elements } \label{table:3.1}
+ \centering
+\begin{tabular}{|l|l|l|l|}
+ \hline
+ \textbf{Statement Element} &
+ \textbf{Attribute} &
+ \textbf{Child Elements} &
+ \textbf{Methods} \\
+ \hline
+ % after \\: \hline or \cline{col1-col2} \cline{col3-col4} ...
+ \tt{<statement>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id \\
+ parameterClass \\
+ resultClass \\
+ listClass \\
+ parameterMap \\
+ resultMap\\
+ cacheModel
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ None
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ Insert \\ Update \\ Delete \\ All query methods
+ \end{minipage}
+ \\
+ \hline
+ \tt{<insert>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id \\
+ parameterClass \\
+ parameterMap
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ \tt{<selectKey>}\\
+ \tt{<generate>}
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ Insert \\ Update \\ Delete
+ \end{minipage}
+\\
+\hline
+ \tt{<update>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id \\
+ parameterClass \\
+ parameterMap \\
+ extends
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ \tt{<generate>}
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ Insert \\ Update \\ Delete
+ \end{minipage}
+ \\
+ \hline
+ \tt{<delete>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id \\
+ parameterClass \\
+ parameterMap \\
+ extends
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ \tt{<generate>}
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ Insert \\ Update \\ Delete
+ \end{minipage}
+ \\
+ \hline
+ \tt{<select>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id\\
+ parameterClass\\
+ resultClass\\
+ listClass \\
+ parameterMap \\
+ resultMap \\
+ cacheModel \\
+ extends
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ \tt{<generate>}
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ All query methods
+ \end{minipage}
+ \\
+ \hline
+ \tt{<procedure>} &
+ \begin{minipage}{0.17\textwidth}
+ \vspace{3mm}
+ id\\
+ parameterMap \\
+ resultClass\\
+ resultMap \\
+ cacheModel
+ \vspace{3mm}
+ \end{minipage}
+ &
+ \begin{minipage}{0.22\textwidth}
+ None
+ \end{minipage}
+ &
+ \begin{minipage}{0.2\textwidth}
+ Insert \\ Update \\ Delete \\ All query methods
+ \end{minipage}
+ \\
+ \hline
+\end{tabular}
+\end{table}
+
+\subsection{Stored Procedures}\label{section:3.3.2}
+
+????
+
+\section{The SQL} \label{section:3.3.3}
+If you are not using stored procedures, the most important part of a
+statement-type element is the SQL. You can use any SQL statement that is valid
+for your database system. Since SQLMap passes the SQL through to a standard
+libraries (Adodb for PHP), you can use any statement with SQLMap that you
+could use without SQLMap. You can use whatever functions your database system
+supports, and even send multiple statements, so long as your driver or
+provider supports them.
+
+%If standard, static SQL isn't enough, iBATIS can help you build a dynamic SQL
+%statement. See Section 3.9 for more about Dynamic SQL.
+
+
+\subsection{Escaping XML symbols} Because you are combining SQL and XML in a
+single document, conflicts can occur. The most common conflict is the
+greater-than and less-than symbols (><). SQL statements use these symbols as
+operators, but they are reserved symbols in XML. A simple solution is to
+escape the SQL statements that uses XML reserved symbols within a CDATA
+element. Example~\ref{example:3.6} demonstrates this.
+
+\begin{example}\label{example:3.6}
+Using CDATA to ``escape'' SQL code
+\begin{verbatim}
+<statement id="SelectPersonsByAge" parameterClass="int" resultClass="Person">
+ <![CDATA[
+ SELECT * FROM PERSON WHERE AGE > #value#
+ ]]>
+</statement>
+\end{verbatim}
+\end{example}
+
+\subsection{Auto-Generated Keys}
+Many database systems support auto-generation of primary key fields, as a
+vendor extension. Some vendors pre-generate keys (e.g. Oracle), some vendors
+post-generate keys (e.g. MS-SQL Server and MySQL). In either case, you can
+obtain a pre-generated key using a \tt{<selectKey>} stanza within an
+\tt{<insert>} element. Example~\ref{example:3.7} shows an \tt{<insert>}
+statement for either approach.
+
+\begin{example}\label{example:3.7}
+\normalfont \tt{<insert>} statements using \tt{<selectKey>} stanzas
+\begin{verbatim}
+<!¡ªOracle SEQUENCE Example using .NET 1.1 System.Data.OracleClient -->
+<insert id="insertProduct-ORACLE" parameterClass="product">
+ <selectKey resultClass="int" type="pre" property="Id" >
+ SELECT STOCKIDSEQUENCE.NEXTVAL AS VALUE FROM DUAL
+ </selectKey>
+ insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#)
+</insert>
+
+<!¡ª Microsoft SQL Server IDENTITY Column Example -->
+<insert id="insertProduct-MS-SQL" parameterClass="product">
+ insert into PRODUCT (PRD_DESCRIPTION)
+ values (#description#)
+ <selectKey resultClass="int" type="post" property="id" >
+ select @@IDENTITY as value
+ </selectKey>
+</insert>
+
+<!-- MySQL Example -->
+<insert id="insertProduct-MYSQL" parameterClass="product">
+ insert into PRODUCT (PRD_DESCRIPTION)
+ values (#description#)
+ <selectKey resultClass="int" type="post" property="id" >
+ select LAST_INSERT_ID() as value
+ </selectKey>
+</insert>
+\end{verbatim}
+\end{example}
+
+\subsection{\tt{<generate>} tag}
+You can use SQLMap to execute any SQL statement your application requires.
+When the requirements for a statement are simple and obvious, you may not even
+need to write a SQL statement at all. The \tt{<generate>} tag can be used to
+create simple SQL statements automatically, based on a \tt{<parameterMap>}
+element. The four CRUD statement types (insert, select, update, and delete)
+are supported. For a select, you can select all or select by a key (or keys).
+Example~\ref{example:3.8} shows an example of generating the usual array of
+CRUD statements.
+
+\begin{mybox}{Important:}
+The intended use of the \tt{<generate>} tag is to save developers the trouble
+of coding mundane SQL statements (and only mundane statements). It is not
+meant as a object-to-relational mapping tool. There are many frameworks that
+provide extensive object-to-relational mapping features. The \tt{<generate>}
+tag is not a replacement for any of those. When the \tt{<generate>} tag does
+not suit your needs, use a conventional statement instead.
+\end{mybox}
+
+\begin{example}\label{example:3.8}
+\normalfont Creating the ``usual suspects'' with the \tt{<generate>} tag
+\begin{verbatim}
+ <parameterMap id="insert-generate-params">
+ <parameter property="Name" column="Category_Name"/>
+ <parameter property="Guid" column="Category_Guid" dbType="UniqueIdentifier"/>
+ </parameterMap>
+
+ <parameterMap id="update-generate-params" extends="insert-generate-params">
+ <parameter property="Id" column="Category_Id" />
+ </parameterMap>
+
+ <parameterMap id="delete-generate-params">
+ <parameter property="Id" column="Category_Id" />
+ <parameter property="Name" column="Category_Name"/>
+ </parameterMap>
+
+ <parameterMap id="select-generate-params">
+ <parameter property="Id" column="Category_Id" />
+ <parameter property="Name" column="Category_Name"/>
+ <parameter property="Guid" column="Category_Guid" dbType="UniqueIdentifier"/>
+ </parameterMap>
+
+ <update id="UpdateCategoryGenerate" parameterMap="update-generate-params">
+ <generate table="Categories" by="Category_Id"/>
+ </update>
+
+ <delete id="DeleteCategoryGenerate" parameterMap="delete-generate-params">
+ <generate table="Categories" by="Category_Id, Category_Name"/>
+ </delete>
+
+ <select id="SelectByPKCategoryGenerate" resultClass="Category" parameterClass="Category"
+ parameterMap="select-generate-params">
+ <generate table="Categories" by="Category_Id"/>
+ </select>
+
+ <select id="SelectAllCategoryGenerate" resultClass="Category"
+ parameterMap="select-generate-params">
+ <generate table="Categories" />
+ </select>
+
+ <insert id="InsertCategoryGenerate" parameterMap="insert-generate-params">
+ <selectKey property="Id" type="post" resultClass="int">
+ select @@IDENTITY as value
+ </selectKey>
+ <generate table="Categories" />
+ </insert>
+\end{verbatim}
+\end{example}
+The tag generates ANSI SQL, which should work with any compliant database.
+Special types, such as blobs, are not supported, and vendor-specific types are
+also not supported. But, the generate tag does keep the simple things simple.
+
+\begin{mybox}{Note:}
+The SQL is generated when the DataMapper instance is built and can be cached
+afterward, so there is no performance impact at execution time.
+\end{mybox}
+
+The generate tag supports two attributes :
+\begin{table}[!htb]\centering\label{table:3.2}
+\caption{\tt{<generate>} attributes}
+\begin{tabular}{|l|l|l|}
+ \hline
+ % after \\: \hline or \cline{col1-col2} \cline{col3-col4} ...
+ \textbf{Attribute} & \textbf{Description} & \textbf{Required} \\
+ \hline
+ table & specifies the table name to use in the SQL statement. & yes \\
+ \hline
+ by & specifies the columns to use in a WHERE clause & no \\
+ \hline
+\end{tabular}
+\end{table}
+
+\section{Statement-type Element Attributes}\label{section:3.3.4}
+The six statement-type elements take various attributes. See
+Section~\ref{section:3.3.1} for a table itemizing which attributes each
+element-type accepts. The individual attributes are described in the sections
+that follow.
+
+\subsection{\tt{id} attribute}
+The required \tt{id} attribute provides a name for this statement, which must
+be unique within this \tt{<SqlMap>}.
+
+\subsection{\tt{parameterMap} attribute}
+A Parameter Map defines an ordered list of values that match up with the ``?''
+placeholders of a standard, parameterized query statement.
+Example~\ref{example:3.9} shows a \tt{<parameterMap>} and a corresponding
+\tt{<statement>}.
+
+\begin{example}\label{example:3.9}
+A \tt{parameterMap} and corresponding statement
+\begin{verbatim}
+<parameterMap id="insert-product-param" class="Product">
+ <parameter property="id"/>
+ <parameter property="description"/>
+</parameterMap>
+
+<statement id="insertProduct" parameterMap="insert-product-param">
+ insert into PRODUCT (PRD_ID, PRD_DESCRIPTION) values (?,?);
+</statement>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.9}, the Parameter Map describes two parameters that
+will match, in order, two placeholders in the SQL statement. The first ``?''
+is replaced by the value of the \tt{id} property. The second is replaced with
+the \tt{description} property.
+
+SQLMap also supports named, inline parameters, which most developers seem to
+prefer. However, Parameter Maps are useful when the SQL must be kept in a
+standard form or when extra information needs to be provided. For more about
+Parameter Maps see Chapter~\ref{section:3.4}.
+
+\subsection{\tt{parameterClass} attribute }
+If a \tt{parameterMap} attribute is not specified, you may specify a
+\tt{parameterClass} instead and use inline parameters (see
+Section~\ref{section:3.4.3}). The value of the \tt{parameterClass} attribute
+can be any existing PHP class name. Example~\ref{example:3.10} shows a
+statement using a PHP class named \tt{Product} in \tt{parameterClass}
+attribute.
+
+\begin{example}\label{example:3.10}
+Specify the \tt{parameterClass} with a PHP class name.
+\begin{verbatim}
+<statement id="statementName" parameterClass="Product">
+ insert into PRODUCT values (#id#, #description#, #price#)
+</statement>
+\end{verbatim}
+\end{example}
+
+\subsection{\tt{resultMap} attribute}
+A Result Map lets you control how data is extracted from the result of a
+query, and how the columns are mapped to object properties.
+Example~\ref{example:3.11} shows a \tt{<resultMap>} element and a
+corresponding \tt{<statement>} element.
+\begin{example}\label{example:3.11}
+A \tt{<resultMap>} and corresponding \tt{<statement>}
+\begin{verbatim}
+<resultMap id="select-product-result" class="product">
+ <result property="id" column="PRD_ID"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+</resultMap>
+
+<statement id="selectProduct" resultMap="select-product-result">
+ select * from PRODUCT
+</statement>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.11}, the result of the SQL query will be mapped to
+an instance of the \tt{Product} class using the ``select-product-result''
+\tt{<resultMap>}. The \tt{<resultMap>} says to populate the \tt{id} property
+from the \tt{PRD\_ID} column, and to populate the \tt{description} property
+from the \tt{PRD\_DESCRIPTION} column.
+
+\begin{mybox}{Tip:}
+In Example~\ref{example:3.11}, note that using `` select * '' is supported. If
+you want all the columns, you don't need to map them all individually. (Though
+many developers consider it a good practice to always specify the columns
+expected.)
+\end{mybox}
+
+For more about Result Maps, see Chapter~\ref{section:3.5}.
+
+\subsection{\tt{resultClass} attribute}
+If a \tt{resultMap} is not specified, you may specify a \tt{resultClass}
+instead. The value of the \tt{resultClass} attribute can be the name of a PHP
+class or primitives like \tt{integer}, \tt{string}, or \tt{array}. The class
+specified will be automatically mapped to the columns in the result, based on
+the result metadata. The following example shows a \tt{<statement>} element
+with a \tt{resultClass} attribute.
+
+\begin{example}\label{example:3.12}
+A \tt{<statement>} element with \tt{resultClass} attribute
+\begin{verbatim}
+<statement id="SelectPerson" parameterClass="int" resultClass="Person">
+ SELECT
+ PER_ID as Id,
+ PER_FIRST_NAME as FirstName,
+ PER_LAST_NAME as LastName,
+ PER_BIRTH_DATE as BirthDate,
+ PER_WEIGHT_KG as WeightInKilograms,
+ PER_HEIGHT_M as HeightInMeters
+ FROM PERSON
+ WHERE PER_ID = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.12}, the \tt{Person} class has properties including:
+\tt{Id}, \tt{FirstName}, \tt{LastName}, \tt{BirthDate},
+\tt{WeightInKilograms}, and \tt{HeightInMeters}. Each of these corresponds
+with the column aliases described by the SQL select statement using the ``as''
+keyword ¨Ca standard SQL feature. When executed, a \tt{Person} object is
+instantiated and populated by matching the object property names to the column
+names from the query.
+
+Using SQL aliases to map columns to properties saves defining a
+\tt{<resultMap>} element, but there are limitations. There is no way to
+specify the types of the output columns (if needed), there is no way to
+automatically load related data such as complex properties.You can overcome
+these limitations with an explicit Result Map (Chapter~\ref{section:3.5}).
+
+\subsection{\tt{listClass} attribute}
+In addition to providing the ability to return an \tt{TList} of objects, the
+DataMapper supports the use of custom collection: a class that implements
+\tt{ArrayAccess}. The following is an example of a TList (it implements
+ArrayAccess) class that can be used with the DataMapper.
+
+\begin{example}\label{example:3.13}
+An \tt{ArrayAccess} implementation, by extending \tt{TList}.
+\begin{verbatim}
+class AccountCollection extends TList
+{
+ public function addRange($accounts)
+ {
+ foreach($accounts as $account)
+ $this->add($account);
+ }
+
+ public function copyTo(TList $array)
+ {
+ $array->copyFrom($this);
+ }
+}
+\end{verbatim}
+\end{example}
+An \tt{ArrayAccess} class can be specified for a select statement through the
+\tt{listClass} attribute. The value of the \tt{listClass} attribute is the
+full name of a PHP class that implements \tt{ArrayAccess}. The statement
+should also indicate the \tt{resultClass} so that the DataMapper knows how to
+handle the type of objects in the collection. The \tt{resultClass} specified
+will be automatically mapped to the columns in the result, based on the result
+metadata. The following example shows a \tt{<statement>} element with a
+\tt{listClass} attribute.
+
+\begin{example}\label{example:3.14}
+A \tt{<statement>} element with \tt{listClass} attribute
+\begin{verbatim}
+<statement id="GetAllAccounts"
+ listClass="AccountCollection"
+ resultClass="Account">
+ select
+ Account_ID as Id,
+ Account_FirstName as FirstName,
+ Account_LastName as LastName,
+ Account_Email as EmailAddress
+ from Accounts
+ order by Account_LastName, Account_FirstName
+</statement>
+\end{verbatim}
+\end{example}
+
+\subsection{\tt{cacheModel} attribute}
+If you want to cache the result of a query, you can specify a Cache Model as
+part of the \tt{<statement>} element. Example~\ref{example:3.15} shows a
+\tt{<cacheModel>} element and a corresponding \tt{<statement>}.
+
+\begin{example}\label{example:3.15}
+A \tt{<cacheModel>} element with its corresponding \tt{<statement>}
+\begin{verbatim}
+<cacheModel id="product-cache" implementation="LRU">
+ <flushInterval hours="24"/>
+ <flushOnExecute statement="insertProduct"/>
+ <flushOnExecute statement="updateProduct"/>
+ <flushOnExecute statement="deleteProduct"/>
+ <property name="size" value="1000" />
+</cacheModel>
+
+<statement id="selectProductList" parameterClass="int" cacheModel="product-cache">
+ select * from PRODUCT where PRD_CAT_ID = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.15}, a cache is defined for products that uses a
+Least Recently Used [LRU] type and flushes every 24 hours or whenever
+associated update statements are executed. For more about Cache Models, see
+Section~\ref{section:3.8}.
+
+\subsection{\tt{extends} attribute}
+When writing Sql, you often encounter duplicate fragments of SQL. SQLMap
+offers a simple yet powerful attribute to reuse them.
+
+\begin{verbatim}
+<select id="GetAllAccounts"
+ resultMap="indexed-account-result">
+select
+ Account_ID,
+ Account_FirstName,
+ Account_LastName,
+ Account_Email
+from Accounts
+</select>
+
+<select id="GetAllAccountsOrderByName"
+ extends="GetAllAccounts"
+ resultMap="indexed-account-result">
+ order by Account_FirstName
+</select>
+\end{verbatim}
diff --git a/docs/sqlmap/latex/ch4.tex b/docs/sqlmap/latex/ch4.tex new file mode 100644 index 00000000..a4cbc937 --- /dev/null +++ b/docs/sqlmap/latex/ch4.tex @@ -0,0 +1,306 @@ +\chapter{Parameter Maps and Inline Parameters}\label{section:3.4}
+Most SQL statements are useful because we can pass them values at runtime.
+Someone wants a database record with the ID 42, and we need to merge that ID
+number into a select statement. A list of one or more parameters are passed at
+runtime, and each placeholder is replaced in turn. This is simple but labor
+intensive, since developers spend a lot of time counting symbols to make sure
+everything is in sync.
+
+\begin{mybox}{Note:}
+Preceding sections briefly touched on inline parameters, which automatically
+map properties to named parameters. Many iBATIS developers prefer this
+approach. But others prefer to stick to the standard, anonymous approach to
+SQL parameters by using parameter maps. Sometimes people need to retain the
+purity of the SQL statements; other times they need the detailed specification
+offered by parameter maps due to database or provider-specific information
+that needs to be used.
+\end{mybox}
+
+\section{Parameter Map}
+A Parameter Map defines an ordered list of values that match up with the
+placeholders of a parameterized query statement. While the attributes
+specified by the map still need to be in the correct order, each parameter is
+named. You can populate the underlying class in any order, and the Parameter
+Map ensures each value is passed in the correct order.
+
+Parameter Maps can be provided as an external element and \emph{inline}.
+Example~\ref{example:3.16} shows an external Parameter Map.
+
+\begin{example}\label{example:3.16}
+An external Parameter Map
+\begin{verbatim}
+<parameterMap id="parameterMapIdentifier"
+ [extends="[sqlMapNamespace.]parameterMapId"]>
+ <parameter
+ property ="propertyName"
+ [column="columnName"]
+ [dbType="databaseType"]
+ [type="propertyCLRType"]
+ [nullValue="nullValueReplacement"]
+ [size="columnSize"]
+ [precision="columnPrecision"]
+ [scale="columnScale"]
+ [typeHandler="class.name"]
+ <parameter ... ... />
+ <parameter ... ... />
+</parameterMap>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.16}, the parts in [brackets] are optional. The
+\tt{parameterMap} element only requires the id attribute.
+Example~\ref{example:3.17} shows a typical \tt{<parameterMap>}.
+
+\begin{example}\label{example:3.17}
+A typical \tt{<parameterMap>} element
+\begin{verbatim}
+<parameterMap id="insert-product-param" class="Product">
+ <parameter property="description" />
+ <parameter property="id"/>
+</parameterMap>
+
+<statement id="insertProduct" parameterMap="insert-product-param">
+ insert into PRODUCT (PRD_DESCRIPTION, PRD_ID) values (?,?);
+</statement>
+\end{verbatim}
+\end{example}
+
+\begin{mybox}{Note:}
+Parameter Map names are always local to the Data Map definition file where
+they are defined. You can refer to a Parameter Map in another Data Map
+definition file by prefixing the \tt{id} of the Parameter Map with the
+namespace of the Data Map (set in the \tt{<sqlMap>} root element). If the
+Parameter Map in Example~\ref{example:3.17} were in a Data Map named
+``Product'', it could be referenced from another file using
+``Product.insert-product-param''.
+\end{mybox}
+
+\subsection{\tt{<parameterMap>} attributes} The \tt{<parameterMap>} element
+accepts two attributes: \tt{id} (required) and \tt{extends} (optional).
+
+\subsubsection{\tt{id} attribute} The required \tt{id} attribute provides a
+unique identifier for the \tt{<parameterMap>} within this Data Map.
+
+\subsubsection{\tt{extends} attribute}
+The optional \tt{extends} attribute can be set to the name of another
+\tt{parameterMap} upon which to base this \tt{parameterMap}. All properties of
+the super \tt{parameterMap} will be included as part of this
+\tt{parameterMap}, and values from the super \tt{parameterMap} are set before
+any values specified by this \tt{parameterMap}. The effect is similar to
+extending a class.
+
+\section{\tt{<parameter>} Elements}
+The \tt{<parameterMap>} element holds one or more parameter child elements
+that map object properties to placeholders in a SQL statement. The sections
+that follow describe each of the attributes.
+
+\subsection{\tt{property} attribute}
+The \tt{property} attribute of \tt{<parameter>} is the name of a property of
+the parameter object. It may also be the name of an entry in an array. The
+name can be used more than once depending on the number of times it is needed
+in the statement. (In an update, you might set a column that is also part of
+the where clause.)
+
+\subsection{\tt{direction} attribute}
+The \tt{direction} attribute may be used to indicate a stored procedure
+parameter's direction.
+
+\subsection{\tt{column} attribute}
+The \tt{column} attribute is used to define to the name of a parameter used by
+a stored procedure.
+
+\begin{table}[!h]\centering\label{table:3.3}
+\caption{Parameter \tt{direction} attribute values }
+\begin{tabular}{|l|l|}
+ \hline
+ % after \\: \hline or \cline{col1-col2} \cline{col3-col4} ...
+ \textbf{Value} & \textbf{Description}\\
+ \hline
+ Input & input-only \\
+ \hline
+ Output & output-only \\
+ \hline
+ InputOutput & bidirectional \\
+ \hline
+\end{tabular}
+\end{table}
+
+\subsection{\tt{dbType} attribute}
+The \tt{dbType} attribute is used to explicitly specify the database column
+type of the parameter to be set by this property. This attribute is normally
+only required if the column is nullable. Although, another reason to use the
+\tt{dbType} attribute is to explicitly specify date types. Most SQL databases
+have more than one \tt{datetime} type. Usually, a database has at least three
+different types (DATE, DATETIME, TIMESTAMP). In order for the value to map
+correctly, you might need to specify the column's \tt{dbType}.
+
+\begin{mybox}{Note:}
+Most providers only need the \tt{dbType} specified for nullable columns. In
+this case, you only need to specify the type for the columns that are
+nullable.
+\end{mybox}
+
+\subsection{\tt{type} attribute}
+The \tt{type} attribute is used to specify the type of the parameter's
+property. This attribute is useful when passing \tt{InputOutput} and
+\tt{Output} parameters into stored procedures. The framework uses the
+specified type to properly handle and set the parameter object's properties
+with the procedure's output values after execution.
+
+%If the attribute type is not set and the framework cannot otherwise determine
+%the type, the type is assumed to be an StdObject. Section~\ref{section:6}
+%details the types and available aliases that have pre-built support in the
+%framework.
+
+\subsection{\tt{nullValue} attribute}\label{section:nullValueParameter}
+The \tt{nullValue} attribute can be set to any valid value (based on property
+type). The \tt{nullValue} attribute is used to specify an outgoing null value
+replacement. What this means is that when the value is detected in the object
+property, a NULL will be written to the database (the opposite behavior of an
+inbound null value replacement). This allows you to use a magic null number in
+your application for types that do not support null values (such as int,
+double, float). When these types of properties contain a matching null value
+(for example, say, $-9999$), a NULL will be written to the database instead of
+the value.
+
+
+\begin{mybox}{Tip:}
+For round-trip transparency of null values, you must also specify database
+columns null value replacements in your Result Map (see
+Chapter~\ref{section:3.5}).
+\end{mybox}
+
+
+\subsection{\tt{size} attribute}
+The \tt{size} attribute sets the maximum size of the data within the column.
+
+\subsection{\tt{precision} attribute}
+The \tt{precision} attribute is used to set the maximum number of digits used
+to represent the property value.
+
+\subsection{\tt{scale} attribute}
+The \tt{scale} attribute sets the number of decimal places used to resolve the
+property value.
+
+\subsection{\tt{typeHandler} attribute}
+The \tt{typeHandler} attribute allows the use of a Custom Type Handler (see
+the Custom Type Handler section). This allows you to extend the DataMapper's
+capabilities in handling types that are specific to your database provider,
+are not handled by your database provider, or just happen to be a part of your
+application design. You can create custom type handlers to deal with storing
+and retrieving booleans from your database for example.
+
+\section{Inline Parameter Maps}\label{section:3.4.3}
+If you prefer to use inline parameters instead of parameter maps, you can add
+extra type information inline too. The inline parameter map syntax lets you
+embed the property name, the property type, the column type, and a null value
+replacement into a parametrized SQL statement. The next four examples shows
+statements written with inline parameters.
+
+\begin{example}\label{example:3.18}
+ A \tt{<statement>} using inline parameters
+\begin{verbatim}
+<statement id="insertProduct" parameterClass="Product">
+ insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
+ values (#id#, #description#)
+</statement>
+\end{verbatim}
+\end{example}
+
+The following example shows how \tt{dbTypes} can be declared inline.
+
+\begin{example}\label{example:3.19}
+ A \tt{<statement>} using an inline parameter map with a type
+\begin{verbatim}
+<statement id="insertProduct" parameterClass="Product">
+ insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
+ values (#id, dbType=int#, #description, dbType=VarChar#)
+</statement>
+\end{verbatim}
+\end{example}
+
+The next example shows how \tt{dbTypes} and null value replacements can also
+be declared inline.
+
+\begin{example}\label{example:3.20}
+A \tt{<statement>} using an inline parameter map with a null value replacement
+\begin{verbatim}
+<statement id="insertProduct" parameterClass="Product">
+ insert into PRODUCT (PRD_ID, PRD_DESCRIPTION)
+ values (#id, dbType=int, nullValue=-999999#, #description, dbType=VarChar#)
+</statement>
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:3.21}
+A more complete example.
+\begin{verbatim}
+<update id="UpdateAccountViaInlineParameters" parameterClass="Account">
+ update Accounts set
+ Account_FirstName = #FirstName#,
+ Account_LastName = #LastName#,
+ Account_Email = #EmailAddress,type=string,dbType=Varchar,nullValue=no_email@provided.com#
+ where
+ Account_ID = #Id#
+</update>
+\end{verbatim}
+\end{example}
+
+\begin{mybox}{Note:}
+Inline parameter maps are handy for small jobs, but when there are a lot of
+type descriptors and null value replacements in a complex statement, an
+industrial-strength, external \tt{parameterMap} can be easier.
+\end{mybox}
+
+\section{Standard Type Parameters}
+In practice, you will find that many statements take a single parameter, often
+an \tt{integer} or a \tt{string}. Rather than wrap a single value in another
+object, you can use the standard library object (string, integer, et cetera)
+as the parameter directly. Example~\ref{example:3.22} shows a statement using
+a standard type parameter.
+
+\begin{example}\label{example:3.22}
+A \tt{<statement>} using standard type parameters
+\begin{verbatim}
+<statement id="getProduct" parameterClass="System.Int32">
+ select * from PRODUCT where PRD_ID = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+Assuming \tt{PRD\_ID} is a numeric type, when a call is made to this Mapped
+Statement, a standard integer can be passed in. The \tt{\#value\#} parameter
+will be replaced with the value of the integer. The name \tt{value} is simply
+a placeholder, you can use another moniker of your choice. Result Maps support
+primitive types as results as well.
+
+For your convenience, the following PHP primitive types are supported.
+\begin{itemize}
+ \item \tt{string}
+ \item \tt{float} or \tt{double}
+ \item \tt{integer} or \tt{int}
+ \item \tt{bool} or \tt{boolean}
+\end{itemize}
+
+\section{Array Type Parameters}
+You can also pass in a array as a parameter object. This would usually be a an
+associative array. Example~\ref{example:3.23} shows a \tt{<statement>} using
+an array for a \tt{parameterClass}.
+
+
+\begin{example}\label{example:3.23}
+A \tt{<statement>} using an array for a \tt{parameterClass}
+\begin{verbatim}
+<statement id="getProduct" parameterClass="array">
+ select * from PRODUCT
+ where PRD_CAT_ID = #catId#
+ and PRD_CODE = #code#
+</statement>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.23}, notice that the SQL in this Mapped Statement
+looks like any other. There is no difference in how the inline parameters are
+used. If an associative array is passed, it must contain keys named \tt{catId}
+and \tt{code}. The values referenced by those keys must be of the appropriate
+type for the column, just as they would be if passed from a properties object.
diff --git a/docs/sqlmap/latex/ch5.tex b/docs/sqlmap/latex/ch5.tex new file mode 100644 index 00000000..076f6f5d --- /dev/null +++ b/docs/sqlmap/latex/ch5.tex @@ -0,0 +1,941 @@ +\chapter{Result Maps}\label{section:3.5}
+Chapter~\ref{section:3.4} describes Parameter Maps and Inline parameters,
+which map object properties to parameters in a database query. Result Maps
+finish the job by mapping the result of a database query (a set of columns) to
+object properties. Next to Mapped Statements, the Result Map is probably one
+of the most commonly used and most important features to understand.
+
+A Result Map lets you control how data is extracted from the result of a
+query, and how the columns are mapped to object properties. A Result Map can
+describe the column type, a null value replacement, and complex property
+mappings including Collections. Example~\ref{example:3.24} shows the structure
+of a \tt{<resultMap>} element.
+
+\begin{example}\label{example:3.24}
+The structure of a \tt{<resultMap>} element.
+\begin{verbatim}
+<resultMap id="resultMapIdentifier"
+ [class="class.name"]
+ [extends="[sqlMapNamespace.]resultMapId"]>
+
+ <result property="propertyName"
+ column="columnName"
+ [columnIndex="columnIndex"]
+ [dbType="databaseType"]
+ [type="propertyCLRType"]
+ [resultMapping="resultMapName"]
+ [nullValue="nullValueReplacement"]
+ [select="someOtherStatementName"]
+ [lazyLoad="true|false"]
+ [typeHandler="class.name"]
+ />
+ <result ... .../>
+ <result ... .../>
+</resultMap>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.24}, the [brackets] indicate optional attributes.
+The \tt{id} attribute is required and provides a name for the statement to
+reference. The \tt{class} attribute is also required, and specifies the full
+name of a PHP class. This is the class that will be instantiated and populated
+based on the result mappings it contains.
+
+The \tt{resultMap} can contain any number of property mappings that map object
+properties to the columns of a result element. The property mappings are
+applied, and the columns are read, in the order that they are defined.
+Maintaining the element order ensures consistent results between different
+drivers and providers.
+
+\begin{mybox}{Note:}
+As with parameter classes, the result class must be a PHP class object or
+array instance.
+\end{mybox}
+
+\section{Extending \tt{resultMaps}}
+The optional \tt{extends} attribute can be set to the name of another
+\tt{resultMap} upon which to base this \tt{resultMap}. All properties of the
+``super'' \tt{resultMap} will be included as part of this \tt{resultMap}, and
+values from the ``super'' \tt{resultMap} are set before any values specified
+by this \tt{resultMap}. The effect is similar to extending a class.
+
+\begin{mybox}{Tip:}
+The ``super'' \tt{resultMap} must be defined in the file before the extending
+\tt{resultMap}. The classes for the super and sub \tt{resultMaps} need not be
+the same, and do not need to be related in any way.
+\end{mybox}
+
+\section{\tt{<resultMap>} attributes}
+The \tt{<resultMap>} element accepts three attributes: \tt{id} (required),
+\tt{class} (optional), and \tt{extends} (optional).
+
+\subsection{\tt{id} attribute}
+The required \tt{id} attribute provides a unique identifier for the
+\tt{<resultMap>} within this Data Map.
+
+\subsection{\tt{class} attribute}
+The optional \tt{class} attribute specifies an object class to use with this
+\tt{<resultMap>}. The full classname must be specified. Any class can be used.
+
+\begin{mybox}{Note:}
+As with parameter classes, the result class must be a PHP class object or
+array instance.
+\end{mybox}
+
+\subsection{\tt{extends} attribute}
+The optional \tt{extends} attribute allows the result map to inherit all of
+the properties of the ``super'' \tt{resultMap} that it extends.
+
+\section{\tt{<result>} Elements}
+
+The \tt{<resultMap>} element holds one or more \tt{<result>} child elements
+that map SQL result sets to object properties.
+
+\subsection{\tt{property} attribute}
+The \tt{property} attribute is the name of a property of the result object
+that will be returned by the Mapped Statement. The name can be used more than
+once depending on the number of times it is needed to populate the results.
+
+\subsection{\tt{column} attribute}
+The \tt{column} attribute value is the name of the column in the result set
+from which the value will be used to populate the property.
+
+\subsection{\tt{columnIndex} attribute}
+The \tt{columnIndex} attribute value is the index of the column in the
+ResultSet from which the value will be used to populate the object property.
+This is not likely needed in 99\% of applications and sacrifices
+maintainability and readability for speed. Some providers may not realize any
+performance benefit, while others will speed up dramatically.
+
+\subsection{\tt{dbType} attribute}
+The \tt{dbType} attribute is used to explicitly specify the database column
+type of the ResultSet column that will be used to populate the object
+property. Although Result Maps do not have the same difficulties with null
+values, specifying the type can be useful for certain mapping types such as
+Date properties. Because an application language has one Date value type and
+SQL databases may have many (usually at least 3), specifying the date may
+become necessary in some cases to ensure that dates (or other types) are set
+correctly. Similarly, String types may be populated by a \tt{VarChar},
+\tt{Char} or \tt{CLOB}, so specifying the type might be needed in those cases
+too.
+
+\subsection{\tt{type} attribute}
+The \tt{type} attribute is used to explicitly specify the property type of the
+parameter to be set. If the attribute \tt{type} is not set and the framework
+cannot otherwise determine the type, the type is assumed to be \tt{StdObject}.
+
+\subsection{\tt{resultMapping} attribute}
+The \tt{resultMapping} attribute can be set to the name of another
+\tt{resultMap} used to fill the property. If the \tt{resultMap} is in an other
+mapping file, you must specified the fully qualified name as :
+
+\begin{verbatim}
+resultMapping="[namespace.sqlMap.]resultMappingId"
+
+resultMapping="Newspaper"
+<!--resultMapping with a fully qualified name.-->
+resultMapping="LineItem.LineItem"
+\end{verbatim}
+
+\subsection{\tt{nullValue} attribute}
+The \tt{nullValue} attribute can be set to any valid value (based on property
+type). The \tt{nullValue} attribute is used to specify an outgoing null value
+replacement. What this means is that when the value is detected in the object
+property, a NULL will be written to the database (the opposite behavior of an
+inbound null value replacement). This allows you to use a ``magic'' null
+number in your application for types that do not support null values (such as
+int, double, float). When these types of properties contain a matching null
+value (say, $-9999$), a NULL will be written to the database instead of the
+value.
+
+If your database has a NULLABLE column, but you want your application to
+represent NULL with a constant value, you can specify it in the Result Map as
+shown in Example~\ref{example:3.25}.
+
+\begin{example}\label{example:3.25}
+Specifying a \tt{nullvalue} attribute in a Result Map
+\begin{verbatim}
+<resultMap id="get-product-result" class="product">
+ <result property="id" column="PRD_ID"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+ <result property="subCode" column="PRD_SUB_CODE" nullValue="-9999"/>
+</resultMap>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.25}, if PRD\_SUB\_CODE is read as NULL, then the
+\tt{subCode} property will be set to the value of $-9999$. This allows you to
+use a primitive type to represent a NULLABLE column in the database. Remember
+that if you want this to work for queries as well as updates/inserts, you must
+also specify the \tt{nullValue} in the Parameter Map (see,
+Section~\ref{section:nullValueParameter}).
+
+\subsection{\tt{select} attribute}
+The \tt{select} attribute is used to describe a relationship between objects
+and to automatically load complex (i.e. user defined) property types. The
+value of the statement property must be the name of another mapped statement.
+The value of the database column (the column attribute) that is defined in the
+same property element as this statement attribute will be passed to the
+related mapped statement as the parameter. More information about supported
+primitive types and complex property mappings/relationships is discussed later
+in this document. The \tt{lazyLoad} attribute can be specified with the
+\tt{select}.
+
+\subsection{\tt{lazyLoad} attribute}
+Use the \tt{lazyLoad} attribute with the \tt{select} attribute to indicate
+whether or not the select statement's results should be lazy loaded. This can
+provide a performance boost by delaying the loading of the select statement's
+results until they are needed/accessed.
+
+\subsection{\tt{typeHandler} attribute}
+The \tt{typeHandler} attribute allows the use of a Custom Type Handler (see
+the Custom Type Handler in the following section). This allows you to extend
+the DataMapper's capabilities in handling types that are specific to your
+database provider, are not handled by your database provider, or just happen
+to be a part of your application design. You can create custom type handlers
+to deal with storing and retrieving booleans from your database for example.
+
+\section{Custom Type Handlers}
+A custom type handler allows you to extend the DataMapper's capabilities in
+handling types that are specific to your database provider, not handled by
+your database provider, or just happen to be part of your application design.
+The SQLMap for PHP DataMapper provides an interface,
+\tt{ITypeHandlerCallback}, for you to use in implementing your custom type
+handler.
+
+\begin{example}\label{example:3.26}
+\tt{ITypeHandlerCallback} interface
+\begin{verbatim}
+interface ITypeHandlerCallback
+{
+ public function getParameter($object);
+
+ public function getResult($string);
+
+ public function createNewInstance();
+}
+\end{verbatim}
+\end{example}
+
+The \tt{getParameter} method allows you to process a \tt{<statement>}
+parameter's value before it is added as an parameter. This enables you to do
+any necessary type conversion and clean-up before the DataMapper gets to work.
+
+The \tt{getResult} method allows you to process a database result value right
+after it has been retrieved by the DataMapper and before it is used in your
+\tt{resultClass}, \tt{resultMap}, or \tt{listClass}.
+
+The \tt{createNewInstance} method allows the DataMapper to create new instance
+of a particular type handled by this callback.
+
+One scenario where custom type handlers are useful are the when you want to
+use date time values in the database. First, consider a very basic TDateTime
+class.
+
+\begin{verbatim}
+class TDateTime
+{
+ private $_datetime;
+
+ public function __construct($datetime=null)
+ {
+ if(!is_null($datetime))
+ $this->setDatetime($datetime);
+ }
+
+ public function getTimestamp()
+ {
+ return strtotime($this->getDatetime());
+ }
+
+ public function getDateTime()
+ {
+ return $this->_datetime;
+ }
+
+ public function setDateTime($value)
+ {
+ $this->_datetime = $value;
+ }
+}
+\end{verbatim}
+
+We can use a custom type handler to intercept result and parameter mapping
+that uses the say ``data'' as one of its property type. The handler can be
+written as follows.
+
+\begin{example}\label{example:3.27}
+A \tt{TDateTime} Type Handler
+\begin{verbatim}
+class TDateTimeHandler implements ITypeHandlerCallback
+{
+ public function getResult($string)
+ {
+ return new TDateTime($string);
+ }
+
+ public function getParameter($parameter)
+ {
+ if($parameter instanceof TDateTime)
+ return $parameter->getTimestamp();
+ else
+ return $parameter;
+ }
+
+ public function createNewInstance()
+ {
+ return new TDateTime;
+ }
+}
+\end{verbatim}
+\end{example}
+
+With our custom type handler we can use the handler in our SqlMaps. To do
+that, we specify it as a basic \tt{<typeHandler>} for all \tt{date} types
+mapped in our SqlMap files
+
+\begin{example}\label{example:3.29}
+\tt{<typeHandler>} in SqlMap.config
+\begin{verbatim}
+[Our SqlMap.config]
+
+<typeHandlers>
+ <typeHandler type="date" callback="TDateTimeHandler"/>
+</typeHandlers>
+
+
+[One of our SqlMap.xml files]
+ <parameterMap id="boc-params">
+ <parameter property="releasedDate" type="date"/>
+ </parameterMap>
+
+ <resultMap id="boc-result" class="BudgetObjectCode">
+ <result property="releasedDate" column="BOC_DATE" type="date"/>
+ </resultMap>
+\end{verbatim}
+\end{example}
+
+%3.5.5. Inheritance Mapping The iBATIS DataMapper supports the implementation
+%of object-oriented inheritance (subclassing) in your object model. There are
+%several developer options for mapping entity classes and subclasses to
+%database results:
+%
+%resultMap for each class resultMap with submaps for a class hierarchy
+%resultMap with extended resultMaps for each subclass You can use the most
+%efficient mapping strategies from a SQL and query performance perspective when
+%using the inheritance mappings of the DataMapper. To implement an inheritance
+%mapping, the resultMap must define one or more columns in your query's
+%resultset that will serve to identify which resultMap should be used to map
+%each result record to a specific subclass. In many cases, you will use one
+%column value for the DataMapper to use in identifying the proper resultMap and
+%subclass. This column is known as a discriminator.
+%
+%For example, we have a table defined in a database that contains Document
+%records. There are five table columns used to store Document IDs, Titles,
+%Types, PageNumbers, and Cities. Perhaps this table belongs to a legacy
+%database, and we need to create an application using this table with a domain
+%model that defines a class hierarchy of different types of Documents. Or
+%perhaps we are creating a new application and database and just want to
+%persist the data found in a set of related classes into one table. In either
+%case, the DataMapper's inheritance mapping feature can help.
+%
+%\begin{verbatim}
+%// Database table Document
+%CREATE TABLE [Documents] (
+% [Document_ID] [int] NOT NULL ,
+% [Document_Title] [varchar] (32) NULL ,
+% [Document_Type] [varchar] (32) NULL ,
+% [Document_PageNumber] [int] NULL ,
+% [Document_City] [varchar] (32) NULL
+%)
+%\end{verbatim}
+%
+%To illustrate this, let's take a look at a few example classes shown below
+%that have a relationship through inheritance and whose properties can be
+%persisted into our Documents table. First, we have a base Document class that
+%has Id and Title properties. Next, we have a Book class that inherits from
+%Document and contains an additional property called PageNumber. Last, we have
+%a Newspaper class that also inherits from Document and contains a City
+%property.
+%
+%Example 3.30. Documents, Books, and Newspapers!
+%
+%\begin{verbatim}
+%// C# class
+%public class Document {
+% private int _id = -1;
+% private string _title = string.Empty;
+%
+% public int Id
+% {
+% get { return _id; }
+% set { _id = value; }
+% }
+%
+% public string Title
+% {
+% get { return _title; }
+% set { _title = value; }
+% }
+%}
+%
+%public class Book : Document {
+% private int _pageNumber = -1;
+%
+% public int PageNumber
+% {
+% get { return _pageNumber; }
+% set { _pageNumber = value; }
+% }
+%}
+%
+%public class Newspaper : Document {
+% private string _city = string.Empty;
+%
+% public string City
+% {
+% get { return _city; }
+% set { _city = value; }
+% }
+%}
+%\end{verbatim}
+%
+%Now that we have our classes and database table, we can start working on our
+%mappings. We can create one <select> statement that returns all columns in the
+%table. To help the DataMapper discriminate between the different Document
+%records, we're going to indicate that the Document\_Type column holds values
+%that will distinguish one record from another for mapping the results into our
+%class hierarchy.
+%
+%\begin{verbatim}
+%// Document mapping file
+%<select id="GetAllDocument" resultMap="document">
+% select
+% Document_Id, Document_Title, Document_Type,
+% Document_PageNumber, Document_City
+% from Documents
+% order by Document_Type, Document_Id
+%</select>
+%
+%<resultMap id="document" class="Document">
+% <result property="Id" column="Document_ID"/>
+% <result property="Title" column="Document_Title"/>
+% <discriminator column="Document_Type" type="string"/>
+% <subMap value="Book" resultMapping="book"/>
+% <subMap value="Newspaper" resultMapping="newspaper"/>
+%</resultMap>
+%
+%<resultMap id="book" class="Book" extends="document">
+% <property="PageNumber" column="Document_PageNumber"/>
+%</resultMap>
+%
+%<resultMap id="newspaper" class="Newspaper" extends="document">
+% <property="City" column="Document_City"/>
+%</resultMap>
+%\end{verbatim}
+%
+%The DataMapper compares the data found in the discriminator column to the
+%different <submap> values using the column value's string equivalence. Based
+%on this string value, iBATIS DataMapper will use the resultMap named "Book" or
+%"Newspaper" as defined in the <submap> elements or it will use the "super"
+%resultMap "Document" if neither of the submap values satisfy the comparison.
+%With these resultMaps, we can implement an object-oriented inheritance mapping
+%to our database table.
+%
+%If you want to use custom logic, you can use the typeHandler attribute of the
+%<discriminator> element to specify a custom type handler for the discriminator
+%column.
+%
+%Example 3.31. Complex disciminator usage with Custom Type Handler
+%
+%\begin{verbatim}
+%<alias>
+% <typeAlias alias="CustomInheritance"
+% type="IBatisNet.DataMapper.Test.Domain.CustomInheritance, IBatisNet.DataMapper.Test"/>
+%</alias>
+%
+%<resultMaps>
+% <resultMap id="document-custom-formula" class="Document">
+% <result property="Id" column="Document_ID"/>
+% <result property="Title" column="Document_Title"/>
+% <discriminator column="Document_Type" typeHandler="CustomInheritance"/>
+% <subMap value="Book" resultMapping="book"/>
+% <subMap value="Newspaper" resultMapping="newspaper"/>
+% </resultMap>
+%</resultMaps>
+%\end{verbatim}
+%
+%The value of the typeHandler attribute specifies which of our classes
+%implements the ITypeHandlerCallback interface. This interface furnishes a
+%GetResult method for coding custom logic to read the column result value and
+%return a value for the DataMapper to use in its comparison to the resultMap's
+%defined <submap> values.
+%
+%Example 3.32. Example ITypeHandlerCallback interface implementation
+%
+%\begin{verbatim}
+%public class CustomInheritance : ITypeHandlerCallback {
+% #region ITypeHandlerCallback members
+%
+% public object ValueOf(string nullValue)
+% {
+% throw new NotImplementedException();
+% }
+%
+% public object GetResult(IResultGetter getter)
+% {
+% string type = getter.Value.ToString();
+%
+% if (type=="Monograph" || type=="Book")
+% {
+% return "Book";
+% }
+% else if (type=="Tabloid" || type=="Broadsheet" || type=="Newspaper")
+% {
+% return "Newspaper";
+% }
+% else
+% {
+% return "Document";
+% }
+%
+% }
+%
+% public void SetParameter(IParameterSetter setter, object parameter)
+% {
+% throw new NotImplementedException();
+% }
+% #endregion
+%}
+%\end{verbatim}
+
+\section{Implicit Result Maps}
+If the columns returned by a SQL statement match the result object, you may
+not need an explicit Result Map. If you have control over the relational
+schema, you might be able to name the columns so they also work as property
+names. In Example~\ref{example:3.33}, the column names and property names
+already match, so a result map is not needed.
+
+\begin{example}\label{example:3.33}
+A Mapped Statement that doesn't need a Result Map
+\begin{verbatim}
+<statement id="selectProduct" resultClass="Product">
+ select
+ id,
+ description
+ from PRODUCT
+ where id = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+Another way to skip a result map is to use column aliasing to make the column
+names match the properties names, as shown in Example~\ref{example:3.34}.
+
+\begin{example}\label{example:3.34}
+A Mapped Statement using column aliasing instead of a Result Map
+\begin{verbatim}
+<statement id="selectProduct" resultClass="Product">
+ select
+ PRD_ID as id,
+ PRD_DESCRIPTION as description
+ from PRODUCT
+ where PRD_ID = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+Of course, these techniques will not work if you need to specify a column
+type, a null value, or any other property attributes.
+
+\section{Primitive Results (i.e. String, Integer, Boolean)}
+Many times, we don't need to return an object with multiple properties. We
+just need a string, integer, boolean, and so forth. If you don't need to
+populate an object, SQLMap can return one of the primitive types instead. If
+you just need the value, you can use a primitive type as a result class, as
+shown in Example~\ref{example:3.35}.
+
+\begin{example}\label{example:3.35}
+Selecting a primitive type
+\begin{verbatim}
+<select id="selectProductCount" resultClass="integer">
+ select count(1)
+ from PRODUCT
+</select>
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:3.36}
+Loading a simple list of product descriptions
+\begin{verbatim}
+<resultMap id="select-product-result" resultClass="System.String">
+ <result property="value" column="PRD_DESCRIPTION"/>
+</resultMap>
+\end{verbatim}
+\end{example}
+
+\section{Maps with ResultMaps}
+Instead of a rich object, sometimes all you might need is a simple key/value
+list of the data, where each property is an entry on the list. If so, Result
+Maps can populate an array instance as easily as property objects. The syntax
+for using an array is identical to the rich object syntax. As shown in Example
+~\ref{example:3.37}, only the result object changes.
+
+\begin{example}\label{example:3.37}
+Result Maps can use arrays.
+\begin{verbatim}
+<resultMap id="select-product-result" class="array">
+ <result property="id" column="PRD_ID"/>
+ <result property="code" column="PRD_CODE"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+ <result property="suggestedPrice" column="PRD_SUGGESTED_PRICE"/>
+</resultMap>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.37}, an array instance would be created for each row
+in the result set and populated with the Product data. The property name
+attributes, like \tt{id}, \tt{code}, and so forth, would be the key of the
+entry, and the value of the mapped columns would be the value of the entry.
+
+As shown in Example~\ref{example:3.38}, you can also use an implicit Result
+Map with an array type.
+
+\begin{example}\label{example:3.38}
+Implicit Result Maps can use arrays too.
+\begin{verbatim}
+<statement id="selectProductCount" resultClass="array">
+ select * from PRODUCT
+</statement>
+\end{verbatim}
+\end{example}
+
+What set of entries is returned by Example~\ref{example:3.38} depends on what
+columns are in the result set. If the set of column changes (because columns
+are added or removed), the new set of entries would automatically be returned.
+
+\begin{mybox}{Note:}
+Certain providers may return column names in upper case or lower case format.
+When accessing values with such a provider, you will have to pass the key name
+in the expected case.
+\end{mybox}
+
+\section{Complex Properties}
+In a relational database, one table will often refer to another. Likewise,
+some of your business objects may include another object or list of objects.
+Types that nest other types are called ``complex types''. You may not want a
+statement to return a simple type, but a fully-formed complex type.
+
+In the database, a related column is usually represented via a 1:1
+relationship, or a 1:M relationship where the class that holds the complex
+property is from the ``many side'' of the relationship and the property itself
+is from the ``one side'' of the relationship. The column returned from the
+database will not be the property we want; it is a key to be used in another
+query.
+
+From the framework's perspective, the problem is not so much loading a complex
+type, but loading each ``complex property''. To solve this problem, you can
+specify in the Result Map a statement to run to load a given property. In
+Example~\ref{example:3.39}, the ``category'' property of the
+``select-product-result'' element is a complex property.
+
+\begin{example}\label{example:3.39}
+A Result Map with a Complex Property
+\begin{verbatim}
+ <resultMap id="select-product-result" class="product">
+ <result property="id" column="PRD_ID"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+ <result property="category" column="PRD_CAT_ID" select="selectCategory"/>
+ </resultMap>
+
+ <resultMap id="select-category-result" class="category">
+ <result property="id" column="CAT_ID"/>
+ <result property="description" column="CAT_DESCRIPTION"/>
+ </resultMap>
+
+ <select id="selectProduct" parameterClass="int" resultMap="select-product-result">
+ select * from PRODUCT where PRD_ID = #value#
+ </select>
+
+ <select id="selectCategory" parameterClass="int" resultMap="select-category-result">
+ select * from CATEGORY where CAT_ID = #value#
+ </select>
+\end{verbatim}
+\end{example}
+
+In Example~\ref{example:3.39}, the framework will use the ``selectCategory''
+statement to populate the ``category'' property. The value of each category is
+passed to the ``selectCategory'' statement, and the object returned is set to
+the category property. When the process completes, each Product instance will
+have the the appropriate category object instance set.
+
+\section{Avoiding N+1 Selects (1:1)}
+A problem with Example~\ref{example:3.39} may be that whenever you load a
+Product, two statements execute: one for the Product and one for the Category.
+For a single Product, this issue may seem trivial. But if you load 10
+products, then 11 statements execute. For 100 Products, instead of one
+statement product statement executing, a total of 101 statements execute. The
+number of statements executing for Example~\ref{example:3.40} will always be
+N+1: 100+1=101.
+
+\begin{example}\label{example:3.40}
+N+1 Selects (1:1)
+\begin{verbatim}
+ <resultMap id="select-product-result" class="product">
+ <result property="id" column="PRD_ID"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+ <result property="category" column="PRD_CAT_ID" select="selectCategory"/>
+ </resultMap>
+
+ <resultMap id="select-category-result" class="category">
+ <result property="id" column="CAT_ID"/>
+ <result property="description" column="CAT_DESCRIPTION"/>
+ </resultMap>
+
+ <!-- This statement executes 1 time -->
+ <select id="selectProducts" parameterClass="int" resultMap="select-product-result">
+ select * from PRODUCT
+ </select>
+
+ <!-- This statement executes N times (once for each product returned above) -->
+ <select id="selectCategory" parameterClass="int" resultMap="select-category-result">
+ select * from CATEGORY where CAT_ID = #value#
+ </select>
+
+\end{verbatim}
+\end{example}
+
+One way to mitigate the problem is to cache the ``selectCategory'' statement .
+We might have a hundred products, but there might only be five categories.
+Instead of running a SQL query or stored procedure, the framework will return
+the category object from it cache. A 101 statements would still run, but they
+would not be hitting the database. (See Chapter~\ref{section:3.8} for more
+about caches.)
+
+Another solution is to use a standard SQL join to return the columns you need
+from the another table. A join can bring all the columns we need over from the
+database in a single query. When you have a nested object, you can reference
+nested properties using a dotted notation, like ``category.description''.
+
+Example~\ref{example:3.41} solves the same problem as
+Example~\ref{example:3.40}, but uses a join instead of nested properties.
+
+\begin{example}\label{example:3.41}
+Resolving complex properties with a join
+\begin{verbatim}
+ <resultMap id="select-product-result" class="product">
+ <result property="id" column="PRD_ID"/>
+ <result property="description" column="PRD_DESCRIPTION"/>
+ <result property="category" resultMapping="Category.CategoryResult" />
+ </resultMap>
+
+ <statement id="selectProduct" parameterClass="int" resultMap="select-product-result">
+ select *
+ from PRODUCT, CATEGORY
+ where PRD_CAT_ID=CAT_ID
+ and PRD_ID = #value#
+ </statement>
+\end{verbatim}
+\end{example}
+
+\begin{mybox}{Lazy Loading vs. Joins (1:1):}
+It's important to note that using a join is not always better. If you are in a
+situation where it is rare to access the related object (e.g. the category
+property of the Product class) then it might actually be faster to avoid the
+join and the unnecessary loading of all category properties. This is
+especially true for database designs that involve outer joins or nullable
+and/or non-indexed columns. In these situations it might be better to use the
+sub-select solution with lazy loading enabled. The general rule of thumb is:
+use the join if you're more likely going to access the associated properties
+than not. Otherwise, only use it if lazy loading is not an option.
+\\
+\\
+If you're having trouble deciding which way to go, don't worry. No matter
+which way you go, you can always change it without impacting your application
+source code. Example~\ref{example:3.40} and \ref{example:3.41} result in
+exactly the same object graph and are loaded using the exact same method call
+from the application. The only consideration is that if you were to enable
+caching, then the using the separate select (not the join) solution could
+result in a cached instance being returned. But more often than not, that
+won't cause a problem (your application shouldn't be dependent on instance
+level equality i.e. ``==='').
+\end{mybox}
+
+\section{Complex Collection Properties}
+It is also possible to load properties that represent lists of complex
+objects. In the database the data would be represented by a M:M relationship,
+or a 1:M relationship where the class containing the list is on the ``one
+side'' of the relationship and the objects in the list are on the ``many
+side''. To load a \tt{TList} of objects, there is no change to the statement
+(see example above). The only difference required to cause the SQLMap
+DataMapper framework to load the property as a \tt{TList} is that the property
+on the business object must be of type \tt{TList}. For example, if a Category
+has a \tt{TList} of Product instances, the mapping would look like this
+(assuming Category has a property called "ProductList" of \tt{TList}.):
+
+\begin{example}\label{example:3.42}
+Mapping that creates a list of complex objects
+\begin{verbatim}
+<resultMaps>
+
+ <resultMap id="select-category-result" class="Category">
+ <result property="Id" column="CAT_ID"/>
+ <result property="Description" column="CAT_DESCRIPTION"/>
+ <result property="ProductList" column="CAT_ID" select="selectProductsByCatId"/>
+ </resultMap>
+
+ <resultMap id="select-product-result" class="Product">
+ <result property="Id" column="PRD_ID"/>
+ <result property="Description" column="PRD_DESCRIPTION"/>
+ </resultMap>
+<resultMaps>
+
+<statements>
+
+ <statement id="selectCategory" parameterClass="int"
+ resultMap="select-category-result">
+ select * from CATEGORY where CAT_ID = #value#
+ </statement>
+
+ <statement id="selectProductsByCatId" parameterClass="int"
+ resultMap="select-product-result">
+ select * from PRODUCT where PRD_CAT_ID = #value#
+ </statement>
+</statements>
+\end{verbatim}
+\end{example}
+
+\section{Avoiding N+1 Select Lists (1:M and M:N)}
+This is similar to the 1:1 situation above, but is of even greater concern due
+to the potentially large amount of data involved. The problem with the
+solution above is that whenever you load a Category, two SQL statements are
+actually being run (one for the Category and one for the list of associated
+Products). This problem seems trivial when loading a single Category, but if
+you were to run a query that loaded ten (10) Categories, a separate query
+would be run for each Category to load its associated list of Products. This
+results in eleven (11) queries total: one for the list of Categories and one
+for each Category returned to load each related list of Products (N+1 or in
+this case 10+1=11). To make this situation worse, we're dealing with
+potentially large lists of data.
+
+\begin{example}\label{example:3.43}
+N+1 Select Lists (1:M and M:N)
+\begin{verbatim}
+<resultMaps>
+
+ <resultMap id="select-category-result" class="Category">
+ <result property="Id" column="CAT_ID"/>
+ <result property="Description" column="CAT_DESCRIPTION"/>
+ <result property="ProductList" column="CAT_ID" select="selectProductsByCatId"/>
+ </resultMap>
+
+ <resultMap id="select-product-result" class="Product">
+ <result property="Id" column="PRD_ID"/>
+ <result property="Description" column="PRD_DESCRIPTION"/>
+ </resultMap>
+<resultMaps>
+
+<statements>
+
+ <!-- This statement executes 1 time -->
+ <statement id="selectCategory" parameterClass="int"
+ resultMap="select-category-result">
+ select * from CATEGORY where CAT_ID = #value#
+ </statement>
+
+ <!-- This statement executes N times (once for each category returned above)
+ and returns a list of Products (1:M) -->
+ <statement id="selectProductsByCatId" parameterClass="int"
+ resultMap="select-product-result">
+ select * from PRODUCT where PRD_CAT_ID = #value#
+ </statement>
+</statements>
+\end{verbatim}
+\end{example}
+
+\subsection{1:N \& M:N Solution?}
+Currently the feature that resolves this issue not implemented, but the
+development discussions are active, and we expect it to be included in a
+future release.
+
+\begin{mybox}{Lazy Loading vs. Joins (1:M and M:N):}
+As with the 1:1 situation described previously, it's important to note that
+using a join is not always better. This is even more true for collection
+properties than it was for individual value properties due to the greater
+amount of data. If you are in a situation where it is rare to access the
+related object (e.g. the ProductList property of the Category class) then it
+might actually be faster to avoid the join and the unnecessary loading of the
+list of products. This is especially true for database designs that involve
+outer joins or nullable and/or non-indexed columns. In these situations it
+might be better to use the sub-select solution with the lazy loading. The
+general rule of thumb is: use the join if you're more likely going to access
+the associated properties than not. Otherwise, only use it if lazy loading is
+not an option.
+\\
+\\
+As mentioned earlier, if you're having trouble deciding which way to go, don't
+worry. No matter which way you go, you can always change it without impacting
+your PHP code. The two examples above would result in exactly the same object
+graph and are loaded using the exact same method call. The only consideration
+is that if you were to enable caching, then the using the separate select (not
+the join) solution could result in a cached instance being returned. But more
+often than not, that won't cause a problem (your application should not be
+dependent on instance level equality i.e. ``==='').
+\end{mybox}
+
+\section{Composite Keys or Multiple Complex Parameters Properties}
+You might have noticed that in the above examples there is only a single key
+being used as specified in the \tt{resultMap} by the \tt{column} attribute.
+This would suggest that only a single column can be associated to a related
+mapped statement. However, there is an alternate syntax that allows multiple
+columns to be passed to the related mapped statement. This comes in handy for
+situations where a composite key relationship exists, or even if you simply
+want to use a parameter of some name other than \tt{\#value\#}. The alternate
+syntax for the column attribute is simply \{param1=column1, param2=column2,
+$\cdots$, paramN=columnN\}. Consider the example below where the PAYMENT table
+is keyed by both Customer ID and Order ID:
+
+\begin{example}\label{example:3.44}
+Mapping a composite key
+\begin{verbatim}
+<resultMaps>
+ <resultMap id="select-order-result" class="order">
+ <result property="id" column="ORD_ID"/>
+ <result property="customerId" column="ORD_CST_ID"/>
+ ...
+ <result property="payments" column="{itemId=ORD_ID, custId=ORD_CST_ID}"
+ select="selectOrderPayments"/>
+ </resultMap>
+<resultMaps>
+
+<statements>
+
+ <statement id="selectOrderPayments" resultMap="select-payment-result">
+ select * from PAYMENT
+ where PAY_ORD_ID = #itemId#
+ and PAY_CST_ID = #custId#
+ </statement>
+</statements>
+\end{verbatim}
+\end{example}
+
+Optionally you can just specify the column names as long as they're in the
+same order as the parameters. For example:
+\begin{verbatim}
+{ORD_ID, ORD_CST_ID}
+\end{verbatim}
+
+\begin{mybox}{Important!}
+Currently the SQLMap DataMapper framework does not automatically resolve
+circular relationships. Be aware of this when implementing parent/child
+relationships (trees). An easy work around is to simply define a second result
+map for one of the cases that does not load the parent object (or vice versa),
+or use a join as described in the ``N+1 avoidance'' solutions.
+\end{mybox}
+
+\begin{mybox}{Note:}
+Result Map names are always local to the Data Map definition file that they
+are defined in. You can refer to a Result Map in another Data Map definition
+file by prefixing the name of the Result Map with the namespace of the SqlMap
+set in the \tt{<sqlMap>} root element.
+\end{mybox}
diff --git a/docs/sqlmap/latex/ch6.tex b/docs/sqlmap/latex/ch6.tex new file mode 100644 index 00000000..09a2be6f --- /dev/null +++ b/docs/sqlmap/latex/ch6.tex @@ -0,0 +1,119 @@ +\chapter{Cache Models}\label{section:3.8}
+Some values in a database are know to change slower than others. To improve
+performance, many developers like to cache often-used data to avoid making
+unnecessary trips back to the database. SQLMap provides its own caching
+system, that you configure through a \tt{<cacheModel>} element.
+
+The results from a query Mapped Statement can be cached simply by specifying
+the \tt{cacheModel} parameter in the statement tag (seen above). A cache model
+is a configured cache that is defined within your DataMapper configuration
+file. Cache models are configured using the \tt{cacheModel} element as
+follows:
+
+\begin{example}\label{example:3.45}
+Configuring a cache using the Cache Model element
+\begin{verbatim}
+<cacheModel id="product-cache" implementation="LRU" >
+ <flushInterval hours="24"/>
+ <flushOnExecute statement="insertProduct"/>
+ <flushOnExecute statement="updateProduct"/>
+ <flushOnExecute statement="deleteProduct"/>
+ <property name="CacheSize" value="100"/>
+</cacheModel>
+\end{verbatim}
+\end{example}
+
+The cache model above will create an instance of a cache named
+``product-cache'' that uses a Least Recently Used (LRU) implementation. The
+value of the \tt{type} attribute is either a class name, or an alias for one
+of the included implementations (see below). Based on the flush elements
+specified within the cache model, this cache will be flushed every 24 hours.
+There can be only one flush interval element and it can be set using hours,
+minutes, seconds or milliseconds. In addition the cache will be flushed
+whenever the \tt{insertProduct}, \tt{updateProduct}, or \tt{deleteProduct}
+mapped statements are executed. There can be any number of ``flush on
+execute'' elements specified for a cache. Some cache implementations may need
+additional properties, such as the ``cache-size'' property demonstrated above.
+In the case of the LRU cache, the size determines the number of entries to
+store in the cache. Once a cache model is configured, you can specify the
+cache model to be used by a mapped statement, for example:
+
+\begin{example}\label{example:3.46}
+Specifying a Cache Model from a Mapped Statement
+\begin{verbatim}
+<statement id="getProductList" cacheModel="product-cache">
+ select * from PRODUCT where PRD_CAT_ID = #value#
+</statement>
+\end{verbatim}
+\end{example}
+
+\section{Cache Implementation}
+The cache model uses a pluggable framework for supporting different types of
+caches. The choice of cache is specified in the ``implementation'' attribute
+of the \tt{cacheModel} element as discussed above. The class name specified
+must be an implementation of the \tt{ISqlMapCache} interface, or one of the
+two aliases discussed below. Further configuration parameters can be passed to
+the implementation via the property elements contained within the body of the
+\tt{cacheModel}. Currently there are 2 implementations included with the PHP
+distribution.
+
+\subsection{Least Recently Used [LRU] Cache} The LRU cache implementation uses
+an Least Recently Used algorithm to determines how objects are automatically
+removed from the cache. When the cache becomes over full, the object that was
+accessed least recently will be removed from the cache. This way, if there is
+a particular object that is often referred to, it will stay in the cache with
+the least chance of being removed. The LRU cache makes a good choice for
+applications that have patterns of usage where certain objects may be popular
+to one or more users over a longer period of time (e.g. navigating back and
+forth between paginated lists, popular search keys etc.).
+
+The LRU implementation is configured as follows:
+\begin{example}\label{example:3.48}
+Configuring a LRU type cache
+\begin{verbatim}
+<cacheModel id="product-cache" implementation="LRU" >
+ <flushInterval hours="24"/>
+ <flushOnExecute statement="insertProduct"/>
+ <flushOnExecute statement="updateProduct"/>
+ <flushOnExecute statement="deleteProduct"/>
+ <property name="CacheSize" value="100"/>
+</cacheModel>
+\end{verbatim}
+\end{example}
+
+Only a single property is recognized by the LRU cache implementation. This
+property, named \tt{CacheSize} must be set to an integer value representing
+the maximum number of objects to hold in the cache at once. An important thing
+to remember here is that an object can be anything from a single string
+instance to an array of object. So take care not to store too much in your
+cache and risk running out of memory and disk space.
+
+\subsection{FIFO Cache}
+The FIFO cache implementation uses an First In First Out algorithm to
+determines how objects are automatically removed from the cache. When the
+cache becomes over full, the oldest object will be removed from the cache. The
+FIFO cache is good for usage patterns where a particular query will be
+referenced a few times in quick succession, but then possibly not for some
+time later.
+
+The FIFO implementation is configured as follows:
+
+\begin{example}\label{example:3.49}
+Configuring a FIFO type cache
+\begin{verbatim}
+<cacheModel id="product-cache" implementation="FIFO" >
+ <flushInterval hours="24"/>
+ <flushOnExecute statement="insertProduct"/>
+ <flushOnExecute statement="updateProduct"/>
+ <flushOnExecute statement="deleteProduct"/>
+ <property name="CacheSize" value="100"/>
+</cacheModel>
+\end{verbatim}
+\end{example}
+
+Only a single property is recognized by the FIFO cache implementation. This
+property, named \tt{CacheSize} must be set to an integer value representing
+the maximum number of objects to hold in the cache at once. An important thing
+to remember here is that an object can be anything from a single String
+instance to an array of object. So take care not to store too much in your
+cache and risk running out of memory and disk space.
diff --git a/docs/sqlmap/latex/ch7.tex b/docs/sqlmap/latex/ch7.tex new file mode 100644 index 00000000..37a6a0f4 --- /dev/null +++ b/docs/sqlmap/latex/ch7.tex @@ -0,0 +1,3 @@ +\chapter{Dynamic SQL}
+
+Not supported in this release.
diff --git a/docs/sqlmap/latex/ch8.tex b/docs/sqlmap/latex/ch8.tex new file mode 100644 index 00000000..7d7e3576 --- /dev/null +++ b/docs/sqlmap/latex/ch8.tex @@ -0,0 +1,413 @@ +\chapter{Installation and Setup}\label{section:4.3}
+\section{Introduction}
+This section explains how to install, configure, and use the SQLMap DataMapper
+with your PHP application.
+
+\section{Installing the DataMapper for PHP}
+There are two steps to using SQLMap DataMapper with your application for the
+first time.
+\begin{itemize}
+ \item Setup the distribution
+ \item Add XML documents
+\end{itemize}
+
+\subsection{Setup the Distribution}
+
+The official site for SQLMap DataMapper for PHP is http://... . The DataMapper
+is availabe as a source distribution in the form of a ZIP archive. To download
+the distributions, follow the link to the Downloads area on the web site, and
+select the the source distribution for the SQLMap PHP DataMapper release. You
+can extract the distribution using a utility like WinZip or the extractor
+built into newer versions of Windows.
+
+Under the distribution's source folder are eight folders that make up the
+SQLMap PHP DataMapper distribution, as shown in Table 4.1.
+
+\begin{table}[!hpt]
+\caption{Folders found in the SQLMap PHP DataMapper source distribution}
+\label{table:4.1}
+ \centering
+\begin{tabular}{|l|l|}
+\hline
+ \textbf{Folder name} & \textbf{Description} \\
+ \hline
+\end{tabular}
+\end{table}
+
+\subsection{Add XML file items}
+After unpacking the source distribution, you will need to add two types of XML
+files to your Web application, or library project (and Test project if you
+have one). These files are:
+
+\begin{description}
+ \item[SqlMap.xml] --
+ A Data Map file that contains your SQL queries. Your project will contain one
+ or more of these files with names such as Account.xml or Product.xml.
+
+ \item[SqlMap.config] --
+ The DataMapper configuration file that is used to specify the locations of your
+ SqlMap.xml files. It is also used to define other DataMapper
+ configuration options such as caching. You will need to include one SqlMap.config
+ file for each data source that your project has.
+\end{description}
+
+As expected, the \tt{SqlMap.config} file must be placed where the DataMapper
+can find them at runtime.
+
+\section{Configuring the DataMapper for PHP}
+The SQLMap PHP DataMapper is configured using a central XML descriptor file,
+usually named \tt{SqlMap.config}, which provides the details for your data
+source, data maps, and other features like caching, and transactions. At
+runtime, your application code will call a class method provided by the SQLMap
+library to read and parse your \tt{SqlMap.config} file. After parsing the
+configuration file, a DataMapper client will be returned by SQLMap for your
+application to use.
+
+\subsection{DataMapper clients}
+Currently, the SQLMap PHP DataMapper framework revolves around the
+\tt{TSqlMapper} class, which acts as a facade to the DataMapper framework API.
+You can create a DataMapper client by instantiating an object of the
+\tt{TSqlMapper} class. An instance of the \tt{TSqlMapper} class (your
+DataMapper client) is created by reading a single configuration file. Each
+configuration file can specify one database or data source. You can of couse
+use multiple DataMapper clients in your application. Just create another
+configuration file and pass the name of that file when the DataMapper client
+is created. The configuration files might use a different account with the
+same database, or reference different databases on different servers. You can
+read from one client and write to another, if that's what you need to do. See
+Section~\ref{section:4.4.1} for more details on building a \tt{TSqlMapper}
+instance, but first, let's take a look at the DataMapper configuration file.
+
+\section{DataMapper Configuration File (SqlMap.config)}
+A sample configuration file for a PHP web application is shown in
+Example~\ref{example:4.1}. Not all configuration elements are required. The
+following sections describe the elements of this \tt{SqlMap.config} file in
+more detail.
+
+\begin{example}\label{example:4.1}
+Sample SqlMap.Config for a PHP Web Application.
+\begin{verbatim}
+<?xml version="1.0" encoding="utf-8"?>
+<sqlMapConfig>
+
+ <provider class="TAdodbProvider" >
+ <datasource ConnectionString="mysql://user:pass@localhost/test1" />
+ </provider>
+
+ <sqlMaps>
+ <sqlMap name="Account" resource="maps/Account.xml"/>
+ <sqlMap name="Order" resource="maps/Order.xml"/>
+ <sqlMap name="Category" resource="maps/Category.xml"/>
+ <sqlMap name="LineItem" resource="maps/LineItem.xml"/>
+ </sqlMaps>
+
+</sqlMapConfig>
+\end{verbatim}
+\end{example}
+
+\section{DataMapper Configuration Elements}
+Sometimes the values we use in an XML configuration file occur in more than
+one element. Often, there are values that change when we move the application
+from one server to another. To help you manage configuration values, you can
+specify a standard properties file (with name=value entries) as part of a
+DataMapper configuration. Each named value in the properties file becomes a
+shell variable that can be used in the DataMapper configuration file and your
+Data Map definition files (see Chapter~\ref{section:3}).
+
+\subsection{\tt{<properties>} attributes}
+The \tt{<properties>} element can accept one \tt{resource} attribute to
+specify the location of the properties file.
+
+\begin{table}[!hpt]
+\caption{Attributes of the \tt{<properties>} element} \label{table:4.3}
+\centering
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Attribute} & \textbf{Description} \\
+ \hline
+ \tt{resource} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Specify the properties file to be loaded from the directory relative to
+ the current file.
+ \vspace{-3mm}\begin{verbatim}
+ resource="properties.config"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+\end{tabular}
+\end{table}
+
+For example, if the ``properties.config'' file contains
+
+\begin{verbatim}
+<?xml version="1.0" encoding="utf-8" ?>
+<settings>
+ <add key="username" value="albert" />
+</settings>
+\end{verbatim}
+
+then all elements in the DataMapper configuration can use the variable
+\tt{\${username}} to insert the value ``albert''. For example:
+
+\begin{verbatim}
+<provider ConnectionString="mysql://${username}:..."
+\end{verbatim}
+
+Properties are handy during building, testing, and deployment by making it
+easy to reconfigure your application for multiple environments.
+
+\subsection{\tt{<property>} element and attributes}
+You can also specify more than one properties file or add property keys and
+values directly into your \tt{SqlMap.config} file by using \tt{<property>}
+elements. For example:
+
+\begin{verbatim}
+<properties>
+ <property resource="myProperties.config"/>
+ <property resource="anotherProperties.config"/>
+ <property key="host" value="ibatis.com" />
+</properties>
+\end{verbatim}
+
+\begin{table}[!hpt]
+\caption{Attributes of the \tt{<property>} element} \label{table:4.3}
+\centering
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Attribute} & \textbf{Description} \\
+ \hline
+ \tt{resource} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Specify the properties file to be loaded from the directory relative to
+ the current file.
+ \vspace{-3mm}\begin{verbatim}
+ resource="properties.config"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{key} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Defines a property key (variable) name
+ \vspace{-3mm}\begin{verbatim}
+ key="username"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{value} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Defines a value that will be used by the DataMapper in place of the
+ the specified property key/variable
+ \vspace{-3mm}\begin{verbatim}
+ value="mydbuser"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+\end{tabular}
+\end{table}
+
+\subsection{The \tt{<typeHandler>} Element}
+The \tt{<typeHandler>} element allows for the configuration and use of a
+Custom Type Handler (see the Custom Type Handler section). This extends the
+DataMapper's capabilities in handling types that are specific to your database
+provider, are not handled by your database provider, or just happen to be a
+part of your application design.
+
+\begin{verbatim}
+ <typeHandler type="date" callback="TDateTimeHandler"/>
+\end{verbatim}
+
+The \tt{<typeHandler>} element has three attributes:
+\begin{table}[!hpt]
+\caption{Attributes of the \tt{<typeHandler>} element} \label{table:4.5}
+\centering
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Attribute} & \textbf{Description} \\
+ \hline
+%
+ \tt{type} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Refers to the name of the type to handle
+ \vspace{-3mm}\begin{verbatim}
+ type="date"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{dbType} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Indicates the provider dbType to handle
+ \vspace{-3mm}\begin{verbatim}
+ dbType="Varchar2"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{callback} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ The custom type handler class name
+ \vspace{-3mm}\begin{verbatim}
+ callback="TDateTimeHandler"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+\end{tabular}
+\end{table}
+
+
+\subsection{The \tt{<provider>} element and attribute}
+The \tt{<provider>} element encloses a \tt{<datasource>} that configure the
+database system for use by the framework.
+\begin{table}[!hpt]
+\caption{Attributes of the \tt{<provider>} element} \label{table:4.3}
+\centering
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Attribute} & \textbf{Description} \\
+ \hline
+ \tt{class} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ The database provider class that extends
+ \tt{TDatabaseProvider}.
+ \vspace{-3mm}\begin{verbatim}
+ class="TAdodbProvider"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+ \end{tabular}
+\end{table}
+
+\subsection{The \tt{<datasource>} element and attributes}
+The \tt{<datasource>} element specifies the connection string.
+Example~\ref{example:4.2} shows sample element MySql.
+
+\begin{example}\label{example:4.2}
+Sample \tt{<provider>} and \tt{<datasource>} elements.
+\begin{verbatim}
+<!-- The ${properties} are defined in an external file, -->
+<!-- but the values could also be coded inline. -->
+
+<!-- Connecting to a MySQL database -->
+<provider class="TAdodbProvider" >
+ <datasource
+ ConnectionString="mysql://${username}:${password}@${host}/${database}" />
+</provider>
+\end{verbatim}
+\end{example}
+
+\begin{table}[!hpt]
+\caption{Attributes of the \tt{<datasource>} element} \label{table:4.4}
+\centering
+\begin{tabular}{|l|l|}
+ \hline
+ \textbf{Attribute} & \textbf{Description} \\
+ \hline
+%
+ \tt{connectionString} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Data Source Name (DSN) connection string.
+ \vspace{-3mm}\begin{verbatim}
+ connectionString="mysql://root:pwd@localhost/mydb"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{driver} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Database driver name (mysql, sqlite, etc.)
+ \vspace{-3mm}\begin{verbatim}
+ driver="mysql"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{host} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ DB host name/IP (and port number) in the format \tt{host[:port]}.
+ \vspace{-3mm}\begin{verbatim}
+ connectionString="mysql://root:pwd@localhost/mydb"
+ \end{verbatim}\vspace{-5mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{username} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Database connection username.\vspace{2mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{password} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Database connection password.\vspace{2mm}
+ \end{minipage}
+ \\
+ \hline
+%
+ \tt{database} &
+ \begin{minipage}{0.7\textwidth}\vspace{2mm}
+ Database name to use in the connection.\vspace{2mm}
+ \end{minipage}
+ \\
+ \hline
+ \end{tabular}
+\end{table}
+
+\begin{mybox}{Tip:}
+ Use Data Source Name (DSN) connection string or specify the
+ necessary individual connection parameters.
+\end{mybox}
+
+\subsection{The \tt{<sqlMap>} Element}
+On a daily basis, most of your work will be with the Data Maps, which are
+covered by Chapter~\ref{section:3}. The Data Maps define the actual SQL
+statements or stored procedures used by your application. The parameter and
+result objects are also defined as part of the Data Map. As your application
+grows, you may have several varieties of Data Map. To help you keep your Data
+Maps organized, you can create any number of Data Map definition files and
+incorporate them by reference in the DataMapper configuration. All of the
+definition files used by a DataMapper instance must be listed in the
+configuration file.
+
+Example~\ref{example:4.3} shows \tt{<sqlMap>} elements for loading a set of
+Data Map definitions. For more about Data Map definition files, see
+Chapter~\ref{section:3}.
+
+\begin{example}\label{example:4.3}
+Specifying \tt{sqlMap} locations
+\begin{verbatim}
+<!-- Relative path from the directory of the
+ current file using a property variable -->
+<sqlMap resource="${root}/Maps/Account.xml"/>
+<sqlMap resource="${root}/Maps/Category.xml"/>
+<sqlMap resource="${root}/Maps/Product.xml"/>
+
+<!-- Full file path with a property variable -->
+<sqlMap resource="/${projectdir}/MyApp/Maps/Account.xml"/>
+<sqlMap resource="/${projectdir}/MyApp/Maps/Category.xml"/>
+<sqlMap resource="/${projectdir}/MyApp/Maps/Product.xml"/>
+\end{verbatim}
+\end{example}
+
+\begin{mybox}{Tip:}
+Since the application root directory location differs by project type
+(Windows, Web, or library), it is best to use a properties variable to
+indicate the relative path when using the \tt{<sqlMap>} \tt{resource}
+attribute. Having a variable defined in a properties file makes it easy to
+change the path to all your Data Mapper configuration resources in one
+location (note the \tt{\$\{projectdir\}} and \tt{\$\{root\}} variables in the
+example above).
+\end{mybox}
diff --git a/docs/sqlmap/latex/ch9.tex b/docs/sqlmap/latex/ch9.tex new file mode 100644 index 00000000..b1ebb522 --- /dev/null +++ b/docs/sqlmap/latex/ch9.tex @@ -0,0 +1,302 @@ +\chapter{Using SQLMap PHP DataMapper}
+The SQLMap DataMapper API provides four core functions:
+
+\begin{itemize}
+ \item build a \tt{TSqlMapper} instance from a configuration file or cache
+ \item execute an update query (including insert and delete).
+ \item execute a select query for a single object
+ \item execute a select query for a list of objects
+\end{itemize}
+
+The API also provides support for retrieving paginated lists and managing
+transactions.
+
+\section{Building a \tt{TSqlMapper} instance}
+An XML document is a wonderful tool for describing a database configuration
+(Chapter~\ref{section:4.3}) or defining a set of data mappings
+(Chapter~\ref{section:3}), but you can't execute XML. In order to use the
+SQLMap configuration and definitions in your PHP application, you need a class
+you can call.
+
+The framework provides service methods that you can call which read the
+configuration file (and any of its definition files) and builds a
+\tt{TSqlMapper} object. The \tt{TSqlMapper} object provides access to the rest
+of the framework. Example~\ref{example:9.4} shows a singleton Mapper that is
+similar to the one bundled with the framework.
+
+\begin{example}\label{example:9.4}
+A Mapper singleton you can call from your own applications
+\begin{verbatim}
+require_once('/path/to/SQLMap/TSqlMapper.php');
+
+class TMapper
+{
+ private static $_mapper;
+
+ public static function configure($configFile)
+ {
+ if(is_null(self::$_mapper))
+ {
+ $builder = new TDomSqlMapBuilder();
+ self::$_mapper = $builder->configure($configFile);
+ }
+ return self::$_mapper;
+ }
+
+ public static function instance()
+ {
+ return self::$_mapper;
+ }
+}
+\end{verbatim}
+\end{example}
+
+To obtain the \tt{TSqlMapper} instance, first configure the mapper once,
+\begin{verbatim}
+TMapper::configure('path/to/sqlmap.config');
+\end{verbatim}
+The \tt{TDomSqlMapBuilder} object will go throught the the \tt{sqlmap.config}
+file and build a \tt{TSqlMapper} instance. To use \tt{TSqlMapper} in your
+application, specify one of the \tt{TSqlMapper} methods (see Section ???).
+Here's an example:
+\begin{verbatim}
+$list = TMapper::instance()->queryForList("PermitNoForYearList", $values);
+\end{verbatim}
+
+\subsection{Multiple Databases}
+If you need access to more than one database from the same application, create
+a DataMapper configuration file for that database and another Mapper class to
+go with it.
+
+\subsection{\tt{TDomSqlMapBuilder} Configuration Options}
+If you find that you already have loaded your DataMapper configuration
+information as a \tt{SimpleXMLElement} instance within your application, the
+\tt{TDomSqlMapBuilder} provides \tt{Configure} overloads for those types as
+well.
+
+\section{Exploring the SQLMap PHP DataMapper API through the \tt{TSqlMapper}}
+The \tt{TSqlMapper} instance acts as a facade to provide access the rest of
+the DataMapper framework. The DataMapper API methods are shown in Example
+4.11.
+
+\begin{example}
+The SQLMap DataMapper API for PHP.
+\begin{verbatim}
+ /* Query API */
+ public function queryForObject($statementName, $parameter=null, $result=null);
+ public function queryForList($statementName, $parameter=null, $result=null,
+ $skip=-1, $max=-1);
+ public function queryForPagedList($statementName, $parameter=null, $pageSize=10);
+ public function queryForMap($statementName, $parameter=null,
+ $keyProperty=null, $valueProperty=null);
+
+ public function insert($statementName, $parameter=null)
+ public function update($statementName, $parameter=null)
+ public function delete($statementName, $parameter=null)
+
+ /* Connection API */
+ public function openConnection()
+ public function closeConnection()
+
+ /* Transaction API */
+ public function beginTransaction()
+ public function commitTransaction()
+ public function rollBackTransaction()
+\end{verbatim}
+\end{example}
+
+Note that each of the API methods accept the name of the Mapped Statement as
+the first parameter. The \tt{statementName} parameter corresponds to the
+\tt{id} of the Mapped Statement in the Data Map definition (see
+Section~\ref{section:3.3}). In each case, a \tt{parameterObject} also may be
+passed. The following sections describe how the API methods work.
+
+\subsection{Insert, Update, Delete}
+\begin{verbatim}
+ public function insert($statementName, $parameter=null)
+ public function update($statementName, $parameter=null)
+ public function delete($statementName, $parameter=null)
+\end{verbatim}
+
+If a Mapped Statement uses one of the \tt{<insert>}, \tt{<update>}, or
+\tt{<delete>} statement-types, then it should use the corresponding API
+method. The \tt{<insert>} element supports a nested \tt{<selectKey>} element
+for generating primary keys (see Section~\ref{section:3.3.3}). If the
+\tt{<selectKey>} stanza is used, then \tt{insert} returns the generated key;
+otherwise a null object is returned. Both the \tt{update} and \tt{delete}
+methods return the number of rows affected by the statement.
+
+\subsection{QueryForObject}
+\begin{verbatim}
+public function queryForObject($statementName, $parameter=null, $result=null);
+\end{verbatim}
+
+If a Mapped Statement is expected to select a single row, then call it using
+\tt{queryForObject}. Since the Mapped Statement definition specifies the
+result class expected, the framework can both create and populate the result
+class for you. Alternatively, if you need to manage the result object
+yourself, say because it is being populated by more than one statement, you
+can use the alternate form and pass your \tt{\$resultObject} as the third
+parameter.
+
+\subsection{QueryForList}
+
+\begin{verbatim}
+public function queryForList($statementName, $parameter=null, $result=null,
+ $skip=-1, $max=-1);
+\end{verbatim}
+If a Mapped Statement is expected to select multiple rows, then call it using
+\tt{queryForList}. Each entry in the list will be an result object populated
+from the corresponding row of the query result. If you need to manage the
+\tt{\$resultObject} yourself, then it can be passed as the third parameter. If
+you need to obtain a partial result, the fourth parameter \tt{\$skip} and
+fifth parameter \tt{\$max} allow you to skip a number of records (the starting
+point) and the maximum number to return.
+
+
+\subsection{QueryForPagedList}
+\begin{verbatim}
+ public function queryForPagedList($statementName, $parameter=null, $pageSize=10);
+\end{verbatim}
+We live in an age of information overflow. A database query often returns more
+hits than users want to see at once, and our requirements may say that we need
+to offer a long list of results a ``page'' at a time. If the query returns
+1000 hits, we might need to present the hits to the user in sets of fifty, and
+let them move back and forth between the sets. Since this is such a common
+requirement, the framework provides a convenience method.
+
+The \tt{TSqlMapPagedList} interface includes methods for navigating through
+pages (\tt{nextPage()}, \tt{previousPage()}, \tt{gotoPage(\$pageIndex)}) and
+also checking the status of the page (\tt{getIsFirstPage()},
+\tt{getIsMiddlePage()}, \tt{getIsLastPage()}, \tt{getIsNextPageAvailable()},
+\tt{getIsPreviousPageAvailable()}, \tt{getCurrentPageIndex()},
+\tt{getPageSize()}). The total number of records available is not accessible
+from the \tt{TSqlMapPagedList} interface, unless a virtual count is defined
+using \tt{setVirtualCount(\$value)}, this should be easily accomplished by
+simply executing a second statement that counts the expected results.
+
+\begin{mybox}{Tip:}
+The \tt{queryForPagedList} method is convenient, but note that a larger set
+(up to 3 times the page size) will first be returned by the database provider
+and the smaller set extracted by the framework. The higher the page size, the
+larger set that will be returned and thrown away. For very large sets, you may
+want to use a stored procedure or your own query that uses \tt{\$skip} and
+\tt{\$max} as parameters in \tt{queryForList}.
+\end{mybox}
+
+\subsection{QueryForMap}
+\begin{verbatim}
+public function queryForMap($statementName, $parameter=null,
+ $keyProperty=null, $valueProperty=null);
+\end{verbatim}
+The \tt{queryForList} methods return the result objects within a \tt{TList} or
+array instance. Alternatively, the \tt{queryForMap} returns a TMap or
+associative array instance. The value of each entry is one of the result
+objects. The key to each entry is indicated by the \tt{\$keyProperty}
+parameter. This is the name of the one of the properties of the result object,
+the value of which is used as the key for each entry. For example, If you
+needed a set of \tt{Employee} objects, you might want them returned as a
+\tt{TMap} keyed by each object's \tt{EmployeeNumber} property.
+
+If you don't need the entire result object in your result, you can add the
+\tt{\$valueProperty} parameter to indicate which result object property should
+be the value of an entry. For example, you might just want the
+\tt{EmployeeName} keyed by \tt{EmployeeNumber}.
+
+\subsection{Transaction}
+The DataMapper API includes methods to demarcate transactional boundaries. A
+transaction can be started, committed and/or rolled back. You can call the
+transaction methods from the \tt{TSqlMapper} instance.
+
+\begin{verbatim}
+// Begin a transactional session using Adodb transaction API
+public function beginTransaction()
+
+// Commit a transaction, uses Adodb transaction API
+public function commitTransaction()
+
+// RollBack a transaction, uses Adodb transaction API
+public void RollBackTransaction()
+\end{verbatim}
+
+\begin{example}\label{example:9.15}
+Using transactions
+\begin{verbatim}
+try
+{
+ $sqlMap->beginTransaction();
+ $item = $sqlMap->queryForObject("getItem", $itemId);
+ $item->setDescription($newDescription);
+ $sqlMap->update("updateItem", $item);
+ $sqlMap->commitTransaction();
+}
+catch
+{
+ $sqlMap->rollBackTransaction();
+}
+\end{verbatim}
+\end{example}
+
+\section{Coding Examples}
+\begin{example}\label{example:10.1}
+Executing Update (insert, update, delete)
+\begin{verbatim}
+$product = new Product();
+$product->setId(1);
+$product->setDescription('Shih Tzui');
+
+$key = $sqlMap->insert('insertProduct', $product);
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.2}
+Executing Query for Object (select)
+\begin{verbatim}
+$key = 1;
+$product = $sqlMap->queryForObject ('getProduct', $key);
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.3}
+Executing Query for Object (select) With Preallocated Result Object
+\begin{verbatim}
+$customer = new Customer();
+
+$sqlMap->beginTransaction();
+
+$sqlMap->queryForObject('getCust', $parameter, $customer);
+$sqlMap->queryForObject('getAddr', $parameter, $customer);
+$sqlMap->commitTransaction();
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.4}
+Executing Query for List (select)
+\begin{verbatim}
+$list = $sqlMap->queryForList ('getProductList');
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.4}
+Executing Query for List (select) With Result Boundaries
+\begin{verbatim}
+$list = $sqlMap->queryForList ('getProductList', $key, null, 0, 40);
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.5}
+Executing Query for Paginated List (select)
+\begin{verbatim}
+$list = $sqlMap->queryForPagedList ('getProductList', null, 10);
+$list->nextPage();
+$list->previousPage();
+\end{verbatim}
+\end{example}
+
+\begin{example}\label{example:10.6}
+Executing Query for Map
+\begin{verbatim}
+ $map = $sqlMap->QueryForMap('getProductList', null, 'productCode');
+ $product = $map['EST-93'];
+\end{verbatim}
+\end{example}
diff --git a/docs/sqlmap/latex/diagram.pdf b/docs/sqlmap/latex/diagram.pdf Binary files differnew file mode 100644 index 00000000..5e64e388 --- /dev/null +++ b/docs/sqlmap/latex/diagram.pdf diff --git a/docs/sqlmap/latex/example1.png b/docs/sqlmap/latex/example1.png Binary files differnew file mode 100644 index 00000000..b5241de6 --- /dev/null +++ b/docs/sqlmap/latex/example1.png diff --git a/docs/sqlmap/latex/grid1.png b/docs/sqlmap/latex/grid1.png Binary files differnew file mode 100644 index 00000000..845b9581 --- /dev/null +++ b/docs/sqlmap/latex/grid1.png diff --git a/docs/sqlmap/latex/grid2.png b/docs/sqlmap/latex/grid2.png Binary files differnew file mode 100644 index 00000000..dcafc33d --- /dev/null +++ b/docs/sqlmap/latex/grid2.png diff --git a/docs/sqlmap/latex/sqlmap.tex b/docs/sqlmap/latex/sqlmap.tex new file mode 100644 index 00000000..57faaab3 --- /dev/null +++ b/docs/sqlmap/latex/sqlmap.tex @@ -0,0 +1,143 @@ +\documentclass{book}
+%\usepackage{graphicx}
+
+\usepackage[pdftex]{hyperref}
+\usepackage[pdftex]{graphicx}
+
+\usepackage{amsmath}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+
+\usepackage{fancyhdr}
+
+\newtheorem{example}{Example}[section]
+
+\renewcommand{\tt}[1]{\texttt{#1}}
+
+%---------- fonts Type 1 -----------------
+\usepackage{times}
+\usepackage[T1]{fontenc}
+\usepackage{textcomp}
+
+%------------------------Page set-up-----------------------------------------
+
+\renewcommand{\baselinestretch}{1.25}
+\setlength{\hoffset}{-1in}
+\setlength{\oddsidemargin}{3.5cm}
+\setlength{\evensidemargin}{3.5cm}
+\setlength{\topmargin}{0cm}
+\setlength{\footskip}{2cm}
+\setlength{\headheight}{14pt}
+\setlength{\marginparwidth}{0cm}
+\setlength{\marginparsep}{0cm}
+\setlength{\marginparpush}{0cm}
+\setlength{\textwidth}{15cm}
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{0.75\baselineskip}
+
+%------------------------------------------------------------------------------
+
+\newsavebox{\fmboxb}
+\newenvironment{mybox}[1]
+ {\vspace{-2mm}\begin{center}\begin{lrbox}{\fmboxb}\hspace{2mm}
+ \begin{minipage}{0.85\textwidth} \vspace{2mm}\small \textbf{#1}}
+ { \vspace{2mm} \end{minipage}
+ \hspace{2mm}\end{lrbox}\fbox{\usebox{\fmboxb}}\end{center}}
+
+
+%---- change link style ----
+\hypersetup{colorlinks, linkcolor=blue, pdfstartview={FitH}}
+
+
+% Pages and Fancyheadings stuff
+%-----------------------------------------------------------------------
+\cfoot{\thepage}
+\fancyhead[LE,RO]{}
+\fancyhead[LO]{\nouppercase{\scshape\rightmark}}
+\fancyhead[RE]{\nouppercase{\scshape\leftmark}}
+%-----------------------------------------------------------------------
+
+%----------------- TITLE --------------
+
+\title{\Huge \bfseries SQLMap PHP DataMapper Application Framework --
+v1.0
+ \thanks{Copyright 2006. All Rights Reserved.}
+}
+\author{Wei Zhuo}
+\date{\today}
+
+
+%-------------- BEGIN DOCUMENT ------------------
+
+
+\begin{document}
+
+\maketitle
+
+\pagestyle{plain}
+\addcontentsline{toc}{chapter}{Contents}
+\pagenumbering{roman}
+\tableofcontents
+
+\chapter*{Legal Notice}
+\addcontentsline{toc}{chapter}{Legal Notice}
+
+Copies of this document may be made for your own use and for distribution to
+others, provided that you do not charge any fee for such copies and further
+provided that each copy contains this Copyright Notice, whether distributed in
+print or electronically.
+
+This document is largely based on the iBATIS.NET -- DataMapper Application
+Framework Developer Guide.
+
+\chapter*{License}
+\addcontentsline{toc}{chapter}{License}
+SQLMap for PHP is free software released under the terms of the following BSD license.\\
+Copyright 2004-2006, PradoSoft (http://www.pradosoft.com)\\
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+\begin{enumerate}
+ \item Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+ \item Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+\item Neither the name of the developer nor the names of its contributors may
+be used to endorse or promote products derived from this software without
+specific prior written permission.
+\end{enumerate}
+
+\begin{verbatim}
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+\end{verbatim}
+
+
+\newpage
+
+\pagestyle{fancyplain}
+\pagenumbering{arabic}
+
+\include{ch1}
+\include{ch2}
+\include{ch3}
+\include{ch4}
+\include{ch5}
+\include{ch6}
+\include{ch7}
+\include{ch8}
+\include{ch9}
+
+\end{document}
diff --git a/docs/sqlmap/latex/sqlmap_tut.tex b/docs/sqlmap/latex/sqlmap_tut.tex new file mode 100644 index 00000000..728fc91f --- /dev/null +++ b/docs/sqlmap/latex/sqlmap_tut.tex @@ -0,0 +1,96 @@ +\documentclass{article}
+%\usepackage{graphicx}
+
+\usepackage[pdftex]{hyperref}
+\usepackage[pdftex]{graphicx}
+
+\usepackage{amsmath}
+\usepackage{amsfonts}
+\usepackage{amssymb}
+
+
+\newtheorem{example}{Example}[section]
+
+\renewcommand{\tt}[1]{\texttt{#1}}
+
+%---------- fonts Type 1 -----------------
+\usepackage{times}
+\usepackage[T1]{fontenc}
+\usepackage{textcomp}
+
+%------------------------Page set-up-----------------------------------------
+
+\renewcommand{\baselinestretch}{1.25}
+\setlength{\hoffset}{-1in}
+\setlength{\oddsidemargin}{3.5cm}
+\setlength{\evensidemargin}{3.5cm}
+\setlength{\topmargin}{0cm}
+\setlength{\footskip}{2cm}
+\setlength{\headheight}{14pt}
+\setlength{\marginparwidth}{0cm}
+\setlength{\marginparsep}{0cm}
+\setlength{\marginparpush}{0cm}
+\setlength{\textwidth}{15cm}
+\setlength{\parindent}{0cm}
+\setlength{\parskip}{0.75\baselineskip}
+
+\hypersetup{colorlinks, linkcolor=blue, pdfstartview={FitH}}
+
+%------------------------------------------------------------------------------
+
+\newsavebox{\fmboxb}
+\newenvironment{mybox}[1]
+ {\vspace{-2mm}\begin{center}\begin{lrbox}{\fmboxb}\hspace{2mm}
+ \begin{minipage}{0.85\textwidth} \vspace{2mm}\small \textbf{#1}}
+ { \vspace{2mm} \end{minipage}
+ \hspace{2mm}\end{lrbox}\fbox{\usebox{\fmboxb}}\end{center}}
+
+%----------------- TITLE --------------
+
+\title{\vspace{-2.5cm} \bfseries SQLMap PHP DataMapper Tutorial
+ \thanks{Copyright 2006. All Rights Reserved.}
+}
+\author{Wei Zhuo}
+\date{\today}
+
+
+%-------------- BEGIN DOCUMENT ------------------
+
+
+\begin{document}
+
+\maketitle
+
+This tutorial takes an ``over-the-shoulder'' Cookbook approach. We'll define a
+simple data access problem and use SQLMap to solve it for us.
+
+
+\section*{Legal Notice}
+
+Copies of this document may be made for your own use and for distribution to
+others, provided that you do not charge any fee for such copies and further
+provided that each copy contains this Copyright Notice, whether distributed in
+print or electronically.
+
+This document is largely based on the iBATIS.NET -- DataMapper Application
+Tutorial.
+
+\subsection*{License Information}
+SQLMap for PHP is free software released under the terms of the following BSD
+license. Copyright 2004-2006, PradoSoft (http://www.pradosoft.com) All rights
+reserved.
+
+\subsection*{Disclaimer}
+SQLMap PHP DataMapper MAKES NO WARRANTIES, EXPRESS OR IMPLIED, AS TO THE
+INFORMATION IN THIS DOCUMENT. The names of actual companies and products
+mentioned herein may be the trademarks of their respective owners.
+
+\subsection*{Remark}
+Original writing by Clinton Begin, Ted Husted and Gilles Bayon.
+
+\include{tut1}
+\include{tut2}
+\include{tut3}
+
+
+\end{document}
diff --git a/docs/sqlmap/latex/tut1.tex b/docs/sqlmap/latex/tut1.tex new file mode 100644 index 00000000..8f7a4a26 --- /dev/null +++ b/docs/sqlmap/latex/tut1.tex @@ -0,0 +1,257 @@ +\section{Test First!}
+
+Let's say that our most important client has a database and one of the tables
+in the database is a list of people. Our client tells us:
+
+``We would like to use a web application to display the people in this table
+and to add, edit, and delete individual records.''
+
+Not a complicated story, but it will cover the CRUD most developers want to
+learn first. :) Let's start with the people table that the client mentioned.
+Since we're keeping it simple, we'll say it's a table in an Access database.
+The table definition is shown as Example~\ref{example:1}.
+
+\begin{example}\label{example:1}
+The Person Table
+\begin{verbatim}
+Name Type Size
+PER_ID Long Integer 4
+PER_FIRST_NAME Text 40
+PER_LAST_NAME Text 40
+PER_BIRTH_DATE Date/Time 8
+PER_WEIGHT_KG Double 8
+PER_HEIGHT_M Double 8
+\end{verbatim}
+\end{example}
+
+\begin{mybox}{Tip:}
+ This example is bundled with a SQLite database file ``Data/test.db''
+ that contains the \tt{Person} table and some data, ready to use.
+\end{mybox}
+
+The first thing our story says is that client would like to display a list of
+people. Example~\ref{example:2} shows our test for that.
+
+\begin{example}\label{example:2}
+Tests/PersonTest.php
+\begin{verbatim}
+<?php
+class PersonTest extends UnitTestCase
+{
+ function testPersonList()
+ {
+ //try it
+ $people = TMapper::instance()->queryForList("SelectAll");
+
+ //test it
+ $this->assertNotNull($people, "Person list is not returned");
+ $this->assertTrue($people->getCount() > 0, "Person list is empty");
+ $person = $people[0];
+ $this->assertNotNull($person, "Person not returned");
+ }
+}
+?>
+\end{verbatim}
+\end{example}
+
+Well, Example 2 sure looks easy enough! We ask a method to ``select all'', and
+it returns a list of person objects. But, what code do we need to write to
+pass this test?
+
+\begin{mybox}{Note:}
+ Save the PersonTest.php into a \tt{Tests} directory. The unit tests are
+ written for the SimpleTest framework (http://simpletest.sf.net).
+\end{mybox}
+
+Now, to setup the testing framework, suppose you have the \tt{SimpleTest}
+framework installed. Then we need to create an entry file to run the tests.
+See the \tt{SimpleTest} documentation for further details on setting up tests.
+
+\begin{example}\label{example:2a}
+Unit test entry file, \tt{run\_tests.php}.
+\begin{verbatim}
+<?php
+require_once('../tests/simpletest/unit_tester.php');
+require_once('../tests/simpletest/reporter.php');
+require_once('../SQLMap/TMapper.php');
+require_once('Models/Person.php');
+
+//supress strict warnings from Adodb.
+error_reporting(E_ALL);
+
+$test = new GroupTest('All tests');
+$test->addTestFile('Tests/PersonTest.php'); $test->run(new HtmlReporter());
+?>
+\end{verbatim}
+\end{example}
+To run the tests, point your browser to the ``run\_test.php'' script file
+served from your web server.
+
+Let's see. The test uses a list of person objects. We could start with a blank
+object, just to satisfy the test, and add the display properties later. But
+let's be naughty and skip a step. Our fully-formed person object is shown in
+Example~\ref{example:3}.
+
+\begin{example}\label{example:3}
+Models/Person.php
+\begin{verbatim}
+<?php
+class Person
+{
+ public $ID = -1;
+ public $FirstName;
+ public $LastName;
+ public $WeightInKilograms = 0.0;
+ public $HeightInMeters = 0.0;
+
+ private $_birthDate;
+
+ //setters and getter for BirthDate
+ public function getBirthDate()
+ {
+ return $this->_birthDate;
+ }
+
+ public function setBirthDate($value)
+ {
+ $this->_birthDate = $value;
+ }
+}
+?>
+\end{verbatim}
+\end{example}
+
+OK, that was fun! The \tt{\$this->assertXXX} methods are built into
+\tt{UnitTestCase} class. So to run Example~\ref{example:2}, we just need the
+\tt{TMapper} object and \tt{queryForList} method. Wonderfully, the SQLMap
+DataMapper framework has a \tt{TMapper}class built into it that will work just
+fine for for us to use in this tutorial, so we don't need to write that
+either.
+
+When the \tt{TMapper->instance()} method is called, an instance of the SQLMap
+\tt{TSqlMapper} class is returned that has various methods available such as
+\tt{queryForList}. In this example, the SQLMap \tt{TSqlMapper->queryForList()}
+method executes our SQL statement (or stored procedure) and returns the result
+as a list. Each row in the result becomes an entry in the list. Along with
+\tt{queryForList()}, there are also \tt{delete()}, \tt{insert()},
+\tt{queryForObject()}, \tt{queryForPagedList()} and a few other methods in the
+SQLMap API. (See Chapter 9 in the SQLMap DataMapper Developer Guide for
+details.)
+
+Looking at Example~\ref{example:2}, we see that the \tt{queryForList()} method
+takes the name of the statement we want to run. OK. Easy enough. But where
+does SQLMap get the ``SelectAll'' statement? Some systems try to generate SQL
+statements for you, but SQLMap specializes in data mapping, not code
+generation. It's our job (or the job of our database administrator) to craft
+the SQL or provide a stored procedure. We then describe the statement in an
+XML element, like the one shown in Example~\ref{example:4}.
+
+\begin{example}\label{example:4}
+We use XML elements to map a database statement to an application object.
+\begin{verbatim}
+<?xml version="1.0" encoding="utf-8" ?>
+<sqlMap>
+ <select id="SelectAll" resultClass="Person">
+ SELECT
+ per_id as ID,
+ per_first_name as FirstName,
+ per_last_name as LastName,
+ per_birth_date as BirthDate,
+ per_weight_kg as WeightInKilograms,
+ per_height_m as HeightInMeters
+ FROM
+ person
+ </select>
+</sqlMap>
+\end{verbatim}
+\end{example}
+
+The SQLMap mapping documents can hold several sets of related elements, like
+those shown in Example~\ref{example:4}. We can also have as many mapping
+documents as we need to help organize our code. Additionally, having multiple
+mapping documents is handy when several developers are working on the project
+at once.
+
+So, the framework gets the SQL code for the query from the mapping, and plugs
+it into a prepared statement. But, how does SQLMap know where to find the
+table's datasource?
+
+Surprise! More XML! You can define a configuration file for each datasource
+your application uses. Example~\ref{example:5} shows a configuration file for
+our SQLite database.
+
+\begin{example}\label{example:5}
+sqlmap.config - a configuration file for our SQLite database
+\begin{verbatim}
+<?xml version="1.0" encoding="UTF-8" ?>
+<sqlMapConfig>
+ <provider class="TAdodbProvider">
+ <datasource driver="sqlite" host="Data/test.db" />
+ </provider>
+ <sqlMaps>
+ <sqlMap resource="Data/person.xml"/>
+ </sqlMaps>
+</sqlMapConfig>
+\end{verbatim}
+\end{example}
+
+The \tt{<provider>} specifies the database provider class, in this case
+\tt{TAdodbProvider} using the Adodb library. The \tt{<datasource>} tag
+specifies the database connection details. In this case, for an SQLite
+database, we just need the driver name, and the host that points to the actual
+SQLite database file.
+
+The last part of the configuration file ("sqlMaps") is where we list our
+mapping documents, like the one shown back in Example~\ref{example:4}. We can
+list as many documents as we need here, and they will all be read when the
+configuration is parsed.
+
+OK, so how does the configuration get parsed?
+
+Look back at Example~\ref{example:2}. The heart of the code is the call to the
+``\tt{TMapper}'' object (under the remark "try it"). The \tt{TMapper} object
+is a singleton that handles the instantiation and configuration of an SQLMap
+\tt{TSqlMapper} object, which provides a facade to the SQLMap DataMapper
+framework API.
+
+The first time that the \tt{TMapper} is called, it reads in the
+\tt{sqlmap.config} file and associated mapping documents to create an instance
+of the \tt{TSqlMapper} class. On subsequent calls, it reuses the
+\tt{TSqlMapper} object so that the configuration is re-read only when files
+change.
+
+The framework comes bundled with a default \tt{TMapper} class for you to use
+immediately to get access to the SQLMap SqlMapper object. If you want to use a
+different name other than \tt{sqlmap.config} at the default location for the
+configuration file, or need to use more than one database and have one
+SqlMapper per database, you can also write your own class to mimic the role of
+the Mapper class view by copying and modifying the standard version.
+
+\begin{mybox}{Tip:}
+ You can also call \tt{TMapper::configure('/path/to/your/sqlmap.config')}
+ to configure the \tt{TMapper} for a specific configuration file.
+\end{mybox}
+
+If we put this all together into a solution, we can ``green bar'' our test. At
+this point you should have the following files.
+\begin{verbatim}
+Data/person.xml % Mapping file.
+Data/test.db % SQLite database file.
+
+Models/Person.php % Person class file.
+
+Tests/PersonTest.php % Unit test case for Person mapping.
+
+run_tests.php % Unit test entry point.
+sqlmap.config % SQLMap configuration file.
+\end{verbatim}
+
+Run the tests by pointing your browser URL to the ``run\_tests.php'' server
+file.
+
+\begin{figure}[!h]
+ \centering
+ \includegraphics[width=0.7\textwidth]{example1}
+ \caption{Green Bar!}
+ \label{fig:diagram}
+\end{figure}
diff --git a/docs/sqlmap/latex/tut2.tex b/docs/sqlmap/latex/tut2.tex new file mode 100644 index 00000000..b5389138 --- /dev/null +++ b/docs/sqlmap/latex/tut2.tex @@ -0,0 +1,128 @@ +\section{Playtest second!}
+Now that we have a passing test, we want to display some results as web pages.
+The following examples utilize the Prado framework to display and manipulate
+the database through SQLMap. Since SQLMap framework and Prado framework solve
+different problems, they are both fairly independent, they can be used
+together or separately.
+
+\subsection{SQLMap and Prado}
+To setup Prado, we need to create the follow files and directory structure
+under our \tt{example/WebView} directory.
+\begin{verbatim}
+assets/ % application public assets
+
+protected/pages/Home.page % default page
+protected/pages/Home.php % default page class
+protected/runtime/ % run time data
+
+protected/application.xml % application configuration
+
+index.php % application entry point
+\end{verbatim}
+
+The \tt{application.xml} and \tt{assets} directory are not necessary but we
+will make use of them later. The \tt{application.xml} is used to define some
+directory aliases and override the data source definitions in the
+\tt{sqlmap.config}. This is because SQLite database files are defined
+relatively, otherwise we don't need to override the data source definitions.
+The example \tt{application.xml} is show in Example~\ref{example:2.0}.
+
+\begin{example}\label{example:2.0}
+Prado application.xml, defines path aliases and override SQLite database
+location.
+\begin{verbatim}
+<?xml version="1.0" encoding="utf-8"?>
+<application id="SQLMap Example" Mode="Debug">
+ <paths>
+ <alias id="Example" path="../../" />
+ <using namespace="System.DataAccess.*" />
+ </paths>
+ <modules>
+ <module id="SQLMap" class="TSQLMap"
+ configFile="Example.sqlmap">
+ <!-- override sqlmap.config's database provider -->
+ <provider class="TAdodbProvider">
+ <datasource driver="sqlite" host="../Data/test.db" />
+ </provider>
+ </module>
+ </modules>
+</application>
+\end{verbatim}
+\end{example}
+
+The entry point to a Prado application in this example is \tt{index.php}.
+Example~\ref{example:2.1} shows the basic \tt{index.php} content.
+\begin{example}\label{example:2.1}
+Prado application entry point, \tt{index.php}.
+\begin{verbatim}
+<?php
+error_reporting(E_ALL);
+require_once('/path/to/prado/framework/prado.php');
+$application=new TApplication;
+$application->run();
+?>
+\end{verbatim}
+\end{example}
+
+Now we are ready to setup a page to display our list of people.
+Example~\ref{example:7} shows the Prado code for our display page. The key
+piece is the TDataGrid.
+
+\begin{example}\label{example:7}
+Prado page for our Person list, \tt{Home.page}.
+\begin{verbatim}
+<!doctype html public "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<head>
+ <title>Person</title>
+</head>
+<body>
+<com:TForm>
+ <h1>Person List</h1>
+ <com:TDataGrid id="personList">
+ <com:TBoundColumn DataField="BirthDate"
+ HeaderText="Birth Date"/>
+ </com:TDataGrid>
+</com:TForm>
+</body>
+</html>
+\end{verbatim}
+\end{example}
+
+Of course, we still need to populate that TDataGrid. Example~\ref{example:8}
+shows the PHP code for \tt{Home.php}. The operative method is \tt{loadData()}.
+The rest is supporting code.
+
+\begin{example}\label{example:8}
+\tt{Home.php} class for our Person list page
+\begin{verbatim}
+<?php
+Prado::using('Example.Models.Person');
+class Home extends TPage
+{
+ private function loadData()
+ {
+ $sqlmap = $this->Application->getModule('SQLMap')->getClient();
+ $this->personList->DataSource = $sqlmap->queryForList('SelectAll');
+ $this->personList->dataBind();
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ $this->loadData();
+ }
+}
+?>
+\end{verbatim}
+\end{example}
+
+If we run this now, we'll get a list like the one shown in
+Figure~\ref{figure:2}.
+\begin{figure}[!h]
+ \centering
+ \includegraphics[width=0.75\textwidth]{grid1}
+ \caption{A quick-and-dirty Person List}
+ \label{figure:2}
+\end{figure}
diff --git a/docs/sqlmap/latex/tut3.tex b/docs/sqlmap/latex/tut3.tex new file mode 100644 index 00000000..4e16ab28 --- /dev/null +++ b/docs/sqlmap/latex/tut3.tex @@ -0,0 +1,227 @@ +\section{Test, test, again ...}
+Of course, tweaking the Person List display is not going to be the end of it.
+Clients always want more, and now ours wants to edit, add, or delete records.
+Let's write some tests for these new tasks, as shown in
+Example~\ref{example:9}.
+
+\begin{example}\label{example:9}
+New stories, new tests
+\begin{verbatim}
+ function testPersonUpdate()
+ {
+ $expect = "wei";
+ $edited = "Nah";
+
+ //get it;
+ $person = TMapper::instance()->queryForObject("Select", 1);
+
+ //test it
+ $this->assertNotNull($person);
+ $this->assertEqual($expect, $person->FirstName);
+
+ //change it
+ $person->FirstName = $edited;
+ TMapper::instance()->update("Update", $person);
+
+ //get it again
+ $person = TMapper::instance()->queryForObject("Select", 1);
+
+ //test it
+ $this->assertEqual($edited, $person->FirstName);
+
+ //change it back
+ $person->FirstName = $expect;
+ TMapper::instance()->update("Update", $person);
+ }
+
+ function testPersonDelete()
+ {
+ //insert it
+ $person = new Person;
+ $person->ID = -1;
+ TMapper::instance()->insert("Insert", $person);
+
+ //delte it
+ $count = TMapper::instance()->delete("Delete", -1);
+ $this->assertEqual(1, $count);
+ }
+\end{verbatim}
+\end{example}
+
+Not the best tests ever written, but for now, they will do :)
+
+To make the new tests work, we'll need some new mapping statements.
+Example~\ref{example:10} shows the complete mapper document that we've called
+\tt{personHelper.xml}.
+
+\begin{example}
+The new and improved mapper document
+\begin{verbatim}
+<?xml version="1.0" encoding="utf-8" ?>
+
+<sqlMap Name="PersonHelper">
+ <select id="Select" parameterClass="int" resultClass="Person">
+ select
+ PER_ID as ID,
+ PER_FIRST_NAME as FirstName,
+ PER_LAST_NAME as LastName,
+ PER_BIRTH_DATE as BirthDate,
+ PER_WEIGHT_KG as WeightInKilograms,
+ PER_HEIGHT_M as HeightInMeters
+ from PERSON
+ WHERE
+ PER_ID = #value#
+ </select>
+
+ <insert id="Insert" parameterClass="Person">
+ insert into PERSON
+ (PER_ID, PER_FIRST_NAME, PER_LAST_NAME,
+ PER_BIRTH_DATE, PER_WEIGHT_KG, PER_HEIGHT_M)
+ values
+ (#ID#, #FirstName#, #LastName#,
+ #BirthDate#, #WeightInKilograms#, #HeightInMeters#)
+ </insert>
+
+ <update id="Update" parameterClass="Person">
+ update PERSON set
+ PER_FIRST_NAME = #FirstName#,
+ PER_LAST_NAME = #LastName#,
+ PER_BIRTH_DATE = #BirthDate#,
+ PER_WEIGHT_KG = #WeightInKilograms#,
+ PER_HEIGHT_M = #HeightInMeters#
+ where PER_ID = #ID#
+ </update>
+
+ <delete id="Delete" parameterClass="int">
+ delete from PERSON
+ where PER_ID = #value#
+ </delete>
+</sqlMap>
+\end{verbatim}
+\end{example}
+Well, waddya know, if run our tests now, we are favored with a green bar!. It
+all works!
+
+\begin{mybox}{Note:}
+Though, of course, things usually do not work perfectly the first time! We
+have to fix this and that, and try, try, again. But SimpleTest makes trying
+again quick and easy. You can changes to the XML mapping documents and rerun
+the tests! No muss, no fuss.
+\end{mybox}
+
+Turning back to our Prado page, we can revamp the TDataGrid to allow in-place
+editing and deleting. To add records, we provide a button after the grid that
+inserts a blank person for client to edit. The page code is shown as
+Example~\ref{example:11}.
+\begin{example}\label{example:11}
+Prado page code for our enhanced TDataGrid
+\begin{verbatim}
+ <com:TDataGrid id="personList"
+ DataKeyField="ID"
+ AutoGenerateColumns="False"
+ OnEditCommand="editPerson"
+ OnUpdateCommand="updatePerson"
+ OnCancelCommand="refreshList"
+ OnDeleteCommand="deletePerson">
+ <com:TBoundColumn DataField="FirstName" HeaderText="First Name" />
+ <com:TBoundColumn DataField="LastName" HeaderText="Last Name" />
+ <com:TBoundColumn DataField="HeightInMeters" HeaderText="Height" />
+ <com:TBoundColumn DataField="WeightInKilograms" HeaderText="Weight" />
+ <com:TEditCommandColumn
+ HeaderText="Edit"
+ UpdateText="Save" />
+ <com:TButtonColumn
+ HeaderText="Delete"
+ Text="Delete"
+ CommandName="delete"/>
+ </com:TDataGrid>
+ <com:TButton Text="Add" OnClick="addNewPerson" />
+\end{verbatim}
+\end{example}
+
+Example~\ref{example:12} shows the corresponding methods from page PHP class.
+
+\begin{example}\label{example:12}
+The page class code for our enhanced TDataGrid
+\begin{verbatim}
+ private function sqlmap()
+ {
+ return $this->Application->getModule('SQLMap')->getClient();
+ }
+
+ private function loadData()
+ {
+ $this->personList->DataSource =
+ $this->sqlmap()->queryForList('SelectAll');
+ $this->personList->dataBind();
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ $this->loadData();
+ }
+
+ protected function editPerson($sender,$param)
+ {
+ $this->personList->EditItemIndex=$param->Item->ItemIndex;
+ $this->loadData();
+ }
+
+ protected function deletePerson($sender, $param)
+ {
+ $id = $this->getKey($sender, $param);
+ $this->sqlmap()->update("Delete", $id);
+ $this->loadData();
+ }
+
+ protected function updatePerson($sender, $param)
+ {
+ $person = new Person();
+ $person->FirstName = $this->getText($param, 0);
+ $person->LastName = $this->getText($param, 1);
+ $person->HeightInMeters = $this->getText($param, 2);
+ $person->WeightInKilograms = $this->getText($param, 3);
+ $person->ID = $this->getKey($sender, $param);
+ $this->sqlmap()->update("Update", $person);
+ $this->refreshList($sender, $param);
+ }
+
+ protected function addNewPerson($sender, $param)
+ {
+ $person = new Person;
+ $person->FirstName = "-- New Person --";
+ $this->sqlmap()->insert("Insert", $person);
+ $this->loadData();;
+ }
+
+ protected function refreshList($sender, $param)
+ {
+ $this->personList->EditItemIndex=-1;
+ $this->loadData();
+ }
+
+ private function getText($param, $index)
+ {
+ $item = $param->Item;
+ return $item->Cells[$index]->Controls[0]->Text;
+ }
+
+ private function getKey($sender, $param)
+ {
+ return $sender->DataKeys[$param->Item->DataSourceIndex];
+ }
+\end{verbatim}
+\end{example}
+
+OK, we are CRUD complete! There's more we could do here. In particular, we
+should add validation methods to prevent client from entering alphabetic
+characters where only numbers can live. But, that's a different Prado
+tutorial, and this is an SQLMap DataMapper tutorial.
+
+\begin{figure}[!h]
+ \centering
+ \includegraphics[width=0.75\textwidth]{grid2}
+ \caption{Person List CRUD}
+ \label{figure:2}
+\end{figure}
|