{"id":1741,"date":"2013-10-01T02:56:08","date_gmt":"2013-10-01T02:56:08","guid":{"rendered":"http:\/\/www.sitekickr.com\/blog\/?p=1741"},"modified":"2013-10-01T02:57:52","modified_gmt":"2013-10-01T02:57:52","slug":"database-validation","status":"publish","type":"post","link":"https:\/\/www.sitekickr.com\/blog\/database-validation\/","title":{"rendered":"Hand some validation over to your database"},"content":{"rendered":"<p>Many of us consider form validation to be a server-side language effort, with a sprinkle of front-end JavaScript to enforce the simpler rules. It can be easily forgotten though, that the database is a great tool for validating data.<\/p>\n<p>There&#39;s a lot of code out there (I&#39;m guilty of this myself) that &quot;works around&quot; the database&#39;s innate ability to validate information inserted into it&#39;s tables. This validation comes in the form of <em>constraints<\/em>. You can define constraints on data, such as primary &amp; foreign keys, the data type of the field or uniqueness.<br \/>\n\t&nbsp;<\/p>\n<h3>Two-query style validation (not recommended)<\/h3>\n<p>When I talk about &quot;working around&quot; the database&#39;s ability to validate data, I&#39;m primarily referring to this practice:<\/p>\n<pre>SELECT id\r\nFROM   wishlist\r\nWHERE  user_id = 2\r\n  AND  product_id  = 3\r\n\r\n&lt;cfif id.recordCount eq 0&gt;\r\n   &lt;!--- insert wishlist item ---&gt;\r\n&lt;cfelse&gt;\r\n   &lt;cfoutput&gt;This item is already in your wishlist.&lt;\/cfoutput&gt;\r\n&lt;\/cfif&gt;<\/pre>\n<p>In the ColdFusion example above, we actually perform a query first, to determine if it&#39;s okay to insert data into the database.<\/p>\n<p>&nbsp;<\/p>\n<h3>Modelling your database table to support validation<\/h3>\n<p>To leverage the power of database validation, we need to make sure we model our database tables properly. The most obvious technique is to use a <strong>primary key<\/strong> or <strong>unique<\/strong> constraint on a single field. For instance, if we needed to ensure that the same email address can not be used twice to create a new user account, we might place a <strong>unique<\/strong> constraint on the <em>email<\/em> field in our users table.<\/p>\n<p>If we wanted to create a wish list feature for our product store, we&#39;d create a &quot;cross reference&quot; table, which links a record in the users table with a record in the products table. But, we wouldn&#39;t want to add the same product to a user&#39;s wish list twice.<\/p>\n<p>We could construct the cross reference table as follows:<\/p>\n<pre><code>CREATE TABLE wishlist (\r\n  user_id int(11) NOT NULL,\r\n  product_id int(11) NOT NULL,\r\n  created datetime NOT NULL,\r\n  PRIMARY KEY (user_id, product_id)\r\n);<\/code><\/pre>\n<p>Constructing a table in this fashion forces uniqueness among the <em>user_id<\/em> and <em>product_id<\/em> fields. If an insert operation attempts the same combination of <em>user_id<\/em> and <em>product_id<\/em> already found in the table, the unique constraint on the primary key will be broken and a duplicate entry error will be thrown.<\/p>\n<p>&nbsp;<\/p>\n<h3>Leaving validation to the database<\/h3>\n<p>Lucky for us, databases communicate constraint related errors to the calling application fairly well. In the case of our primary key constraint, if we attempt to insert a record that breaks the unique constraint on a primary key, the insert operation will fail and an error will be returned to the application.<\/p>\n<p>MySQL returns error code #1062, which means that we&#39;ve attempted to insert a duplicate entry.&nbsp;<\/p>\n<p>Sticking with ColdFusion to demonstrate:<\/p>\n<pre>&lt;cftry&gt;\r\n\r\n    &lt;cfquery&gt;\r\n    INSERT INTO wishlist (\r\n      user_id,\r\n      product_id\r\n      created\r\n    )\r\n    VALUES (\r\n      &lt;cfqueryparam value=&quot;#the_user_id#&quot;&gt;, \r\n      &lt;cfqueryparam value=&quot;#the_product_id#&gt;, \r\n      now()\r\n    )\r\n    &lt;\/cfquery&gt;\r\n\r\n&lt;cfcatch&gt;\r\n\r\n    &lt;cfif cfcatch.NativeErrorCode eq 1062&gt;\r\n\r\n      &lt;cfoutput&gt;This item is already in your wishlist.&lt;\/cfoutput&gt;\r\n\r\n    &lt;\/cfif&gt;\r\n\r\n&lt;\/cfcatch&gt;\r\n&lt;\/cftry&gt;\r\n\r\n\r\n<\/pre>\n<p>We now have a script that &quot;validates&quot; our data in just one query. An unquestionable performance boost from the two-query validation script we started with.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Performing validation at the database level not only protects the integrity of our data, but also presents a performance enhancement while simplifying our application code.<\/p>\n","protected":false},"author":1,"featured_media":1766,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"amp_status":""},"categories":[13],"tags":[82,88,264],"_links":{"self":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts\/1741"}],"collection":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/comments?post=1741"}],"version-history":[{"count":10,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts\/1741\/revisions"}],"predecessor-version":[{"id":1768,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/posts\/1741\/revisions\/1768"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/media\/1766"}],"wp:attachment":[{"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/media?parent=1741"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/categories?post=1741"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sitekickr.com\/blog\/wp-json\/wp\/v2\/tags?post=1741"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}