{"__v":1,"_id":"55097af8dd77250d00736a05","category":{"__v":16,"_id":"550974cc368a56170041475c","project":"55070e814bb83b2500ec9404","version":"550974cb368a561700414757","pages":["55097a674c7c3f2300aabf07","55097a8a4c7c3f2300aabf09","55097a92ad1f0523008ecbd4","55097a9faa9bd525001a065c","55097aa92dd6a11900e6e7b4","55097ab2ad1f0523008ecbd6","55097ac74c7c3f2300aabf0b","55097ace2dd6a11900e6e7b7","55097ad5dd77250d007369fa","55097adead1f0523008ecbd9","55097ae72dd6a11900e6e7b9","55097aefdd77250d007369fc","55097af8dd77250d00736a05","55097aff4c7c3f2300aabf0d","55097b07aa9bd525001a0660","55097b11dd77250d00736a07"],"reference":false,"createdAt":"2015-03-18T11:08:27.090Z","from_sync":false,"order":4,"slug":"database-interaction-through-models","title":"Database Interaction Through Models"},"project":"55070e814bb83b2500ec9404","user":"55070d24d30b3f190011b941","version":{"__v":1,"_id":"550974cb368a561700414757","forked_from":"55070e814bb83b2500ec9407","project":"55070e814bb83b2500ec9404","createdAt":"2015-03-18T12:51:23.709Z","releaseDate":"2015-03-18T12:51:23.709Z","categories":["550974cc368a561700414758","550974cc368a561700414759","550974cc368a56170041475a","550974cc368a56170041475b","550974cc368a56170041475c","550974cc368a56170041475d","550974cc368a56170041475e"],"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"1.4.0","version":"1.4"},"updates":[],"createdAt":"2015-03-18T13:17:44.961Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"auth":"required","params":[],"url":""},"order":14,"body":"Wheels provides some very useful methods for tracking changes to objects. You might think, *Why do I need that? Won't I just know that I changed the object myself?*\n\nWell, that depends on the structure of your code.\n\nAs you work with Wheels and move away from that procedural spaghetti mess you used to call code to a better, cleaner object-oriented approach, you may get a sense that you have lost control of what your code is doing. Your new code is creating objects, they in turn call methods on other objects automatically, methods are being called from multiple places, and so on. Don't worry though, this is a good thing. It just takes a while to get used to, and with the help of some Wheels functionality, it won't take you that long to get used to it either.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"An Example with Callbacks\"\n}\n[/block]\nOne area where this sense of losing control is especially noticeable is when you are using *callbacks* on objects (see the chapter on [Object Callbacks](doc:object-callbacks) for more info). So let's use that for our example.\n\nLet's say you have used a callback to specify that a method should be called whenever a `user` object is saved to the database. You won't know exactly **where** this method was called from. It could have been the user doing it themselves on the website, or it could have been done from your internal administration area. Generally speaking, you don't need to know this either.\n\nOne thing your business logic might need to know though is a way to tell exactly **what** was changed on the object. Maybe you want to handle things differently if the user's last name was changed than if the email address was changed, for example.\n\nLet's look at the methods Wheels provide to make tracking these changes easier for you.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Methods for Tracking Changes\"\n}\n[/block]\nLet's get to coding…\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cfset post = model(\\\"post\\\").findByKey(1)>\\n<cfset result = post.hasChanged()>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nHere we are using the [hasChanged()](doc:haschanged) method to see if any of the object properties has changed.\n\nBy the way, when we are talking about \"change\" in Wheels, we always mean whether or not an object's properties have changed compared to what is stored in the columns they map to in the database table.\n\nIn the case of the above example, the `result` variable will contain `false` because we just fetched the object from the database and did not make any changes to it at all.\n\nWell, let's make a change then. If we didn't, this chapter wouldn't be all that interesting, would it?\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cfset post.title = \\\"A New Post Title\\\">\\n<cfset result = post.hasChanged()>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nNow result will be `true` because what is stored in `post.title` differs from what is stored in the `title` column for this record in the `posts` table (well, unless the title was \"A New Post Title\" even before the change, in which case the result would still be `false`).\n\nWhen calling [hasChanged()](doc:haschanged) with no arguments, Wheels will check **all **properties on the object and return `true` if any of them have changed. If you want to see if a specific property has changed, you can pass in `property=\"title\"` to it or use the dynamic method [XXXHasChanged()](doc:haschanged). Replace `XXX` with the name of the property. In our case, the method would then be named `titleHasChanged()`.\n\nIf you want to see what a value was before a change was made, you can do so by calling [changedFrom()](doc:changedfrom) and passing in the name of a property. This can also be done with the dynamic [XXXChangedFrom()](doc:changedfrom) method.\n\nWhen an object is in a changed state, there are a couple of methods you can use to report back on these changes. [changedProperties()](doc:changedproperties) will give you a list of the property names that have been changed. [allChanges()](doc:allchanges) returns a struct containing all the changes (both the property names and the changed values themselves).\n\nIf you have made changes to an object and for some reason you want to revert it back, you can do so by calling [reload()](doc:reload) on it. This will query the database and update the object properties with their corresponding values from the database.\n\nOK, let's save the object to the database now and see how that affects things.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<cfset post.save()>\\n<cfset result = post.hasChanged()>\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nNow `result` will once again contain `false`. When you save a changed (a.k.a. \"dirty\") object, it clears out its changed state tracking and is considered unchanged again.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Don't Forget the Context\"\n}\n[/block]\nAll of the examples in this chapter look a little ridiculous because it doesn't make much sense to check the status of an object when you changed it manually in your code. As we said in the beginning of the chapter, when put into context of callbacks, multiple methods, etc., it will become clear how useful these methods really are.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Internal Use of Change Tracking\"\n}\n[/block]\nIt's worth noting here that Wheels makes good use of this change tracking internally as well. If you make changes to an object, Wheels is smart enough to only update the changed columns, leaving the rest alone. This is good for a number of reasons but perhaps most importantly for database performance. In high traffic web applications, the bottleneck is often the database, and anything that can be done to prevent unnecessary database access is a good thing.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"One \\\"Gotcha\\\" About Tracking Changes\"\n}\n[/block]\nIf you create a brand new object with the [new()](doc:new) method and call [hasChanged()](doc:haschanged) on it, it will return `true`. The reason for this seemingly unexpected behavior is that change is always viewed from the database's perspective. The [hasChanged()](doc:haschanged) method will return `true` in this case because it is different from what is stored in the database (i.e. it doesn't exist at all in the database yet).\n\nIf you would simply like to know if an object exists in the database or not, you can use the [isNew()](doc:isnew) method.","excerpt":"How to track changes to objects in your application.","slug":"dirty-records","type":"basic","title":"Dirty Records"}

Dirty Records

How to track changes to objects in your application.

Wheels provides some very useful methods for tracking changes to objects. You might think, *Why do I need that? Won't I just know that I changed the object myself?* Well, that depends on the structure of your code. As you work with Wheels and move away from that procedural spaghetti mess you used to call code to a better, cleaner object-oriented approach, you may get a sense that you have lost control of what your code is doing. Your new code is creating objects, they in turn call methods on other objects automatically, methods are being called from multiple places, and so on. Don't worry though, this is a good thing. It just takes a while to get used to, and with the help of some Wheels functionality, it won't take you that long to get used to it either. [block:api-header] { "type": "basic", "title": "An Example with Callbacks" } [/block] One area where this sense of losing control is especially noticeable is when you are using *callbacks* on objects (see the chapter on [Object Callbacks](doc:object-callbacks) for more info). So let's use that for our example. Let's say you have used a callback to specify that a method should be called whenever a `user` object is saved to the database. You won't know exactly **where** this method was called from. It could have been the user doing it themselves on the website, or it could have been done from your internal administration area. Generally speaking, you don't need to know this either. One thing your business logic might need to know though is a way to tell exactly **what** was changed on the object. Maybe you want to handle things differently if the user's last name was changed than if the email address was changed, for example. Let's look at the methods Wheels provide to make tracking these changes easier for you. [block:api-header] { "type": "basic", "title": "Methods for Tracking Changes" } [/block] Let's get to coding… [block:code] { "codes": [ { "code": "<cfset post = model(\"post\").findByKey(1)>\n<cfset result = post.hasChanged()>", "language": "text" } ] } [/block] Here we are using the [hasChanged()](doc:haschanged) method to see if any of the object properties has changed. By the way, when we are talking about "change" in Wheels, we always mean whether or not an object's properties have changed compared to what is stored in the columns they map to in the database table. In the case of the above example, the `result` variable will contain `false` because we just fetched the object from the database and did not make any changes to it at all. Well, let's make a change then. If we didn't, this chapter wouldn't be all that interesting, would it? [block:code] { "codes": [ { "code": "<cfset post.title = \"A New Post Title\">\n<cfset result = post.hasChanged()>", "language": "text" } ] } [/block] Now result will be `true` because what is stored in `post.title` differs from what is stored in the `title` column for this record in the `posts` table (well, unless the title was "A New Post Title" even before the change, in which case the result would still be `false`). When calling [hasChanged()](doc:haschanged) with no arguments, Wheels will check **all **properties on the object and return `true` if any of them have changed. If you want to see if a specific property has changed, you can pass in `property="title"` to it or use the dynamic method [XXXHasChanged()](doc:haschanged). Replace `XXX` with the name of the property. In our case, the method would then be named `titleHasChanged()`. If you want to see what a value was before a change was made, you can do so by calling [changedFrom()](doc:changedfrom) and passing in the name of a property. This can also be done with the dynamic [XXXChangedFrom()](doc:changedfrom) method. When an object is in a changed state, there are a couple of methods you can use to report back on these changes. [changedProperties()](doc:changedproperties) will give you a list of the property names that have been changed. [allChanges()](doc:allchanges) returns a struct containing all the changes (both the property names and the changed values themselves). If you have made changes to an object and for some reason you want to revert it back, you can do so by calling [reload()](doc:reload) on it. This will query the database and update the object properties with their corresponding values from the database. OK, let's save the object to the database now and see how that affects things. [block:code] { "codes": [ { "code": "<cfset post.save()>\n<cfset result = post.hasChanged()>", "language": "text" } ] } [/block] Now `result` will once again contain `false`. When you save a changed (a.k.a. "dirty") object, it clears out its changed state tracking and is considered unchanged again. [block:api-header] { "type": "basic", "title": "Don't Forget the Context" } [/block] All of the examples in this chapter look a little ridiculous because it doesn't make much sense to check the status of an object when you changed it manually in your code. As we said in the beginning of the chapter, when put into context of callbacks, multiple methods, etc., it will become clear how useful these methods really are. [block:api-header] { "type": "basic", "title": "Internal Use of Change Tracking" } [/block] It's worth noting here that Wheels makes good use of this change tracking internally as well. If you make changes to an object, Wheels is smart enough to only update the changed columns, leaving the rest alone. This is good for a number of reasons but perhaps most importantly for database performance. In high traffic web applications, the bottleneck is often the database, and anything that can be done to prevent unnecessary database access is a good thing. [block:api-header] { "type": "basic", "title": "One \"Gotcha\" About Tracking Changes" } [/block] If you create a brand new object with the [new()](doc:new) method and call [hasChanged()](doc:haschanged) on it, it will return `true`. The reason for this seemingly unexpected behavior is that change is always viewed from the database's perspective. The [hasChanged()](doc:haschanged) method will return `true` in this case because it is different from what is stored in the database (i.e. it doesn't exist at all in the database yet). If you would simply like to know if an object exists in the database or not, you can use the [isNew()](doc:isnew) method.