<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1234990956553167879</id><updated>2012-01-06T13:17:11.525-08:00</updated><category term='webservice'/><category term='2009'/><category term='chargeable weight'/><category term='supply chain'/><category term='Code Camp'/><category term='JSR-172'/><category term='transportation management'/><category term='Acuitive Solutions'/><category term='CLDC'/><category term='Enterprise Developer&apos;s Guild'/><category term='BlackBerry'/><category term='BlackBerry JDE'/><category term='Web Service'/><category term='XNA'/><title type='text'>Ramblings of a Software Mechanic</title><subtitle type='html'>Daily challenges in the life of a software developer, and even some solutions.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>6</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-4246423656402626005</id><published>2012-01-06T12:56:00.000-08:00</published><updated>2012-01-06T13:17:11.657-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='supply chain'/><category scheme='http://www.blogger.com/atom/ns#' term='chargeable weight'/><category scheme='http://www.blogger.com/atom/ns#' term='transportation management'/><category scheme='http://www.blogger.com/atom/ns#' term='Acuitive Solutions'/><title type='text'>Catching Up - New Year - New Employer - New Blog Post</title><content type='html'>It has been a very LONG TIME, since my last blog post.  I have left Duke Energy and joined Acuitive Solutions.  In fact, in 4 days I will have been with Acuitive for a year.  Acuitive provides a global &lt;a href="http://www.acuitivesolutions.com/Solutions/WebHostedTMS.aspx" target="_blank"&gt;transportation management system&lt;/a&gt; (TMS) and various other services and tools, including a FREE &lt;a href="http://www.acuitivesolutions.com/Calculator/ChargeableWeight.aspx" target="_blank"&gt;chargeable weight calculator&lt;/a&gt; for freight.  Acuitive is a leader in the &lt;a href="http://www.acuitivesolutions.com" target="_blank"&gt;supply chain&lt;/a&gt; industry, while remaining a quick and agile company.  I'm proud to be working at such a great company, with such great people.&lt;br /&gt;&lt;br /&gt;More to come soon... I promise...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-4246423656402626005?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/4246423656402626005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2012/01/catching-up-new-year-new-employer-new.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4246423656402626005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4246423656402626005'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2012/01/catching-up-new-year-new-employer-new.html' title='Catching Up - New Year - New Employer - New Blog Post'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-5192576295245984693</id><published>2009-11-22T21:20:00.000-08:00</published><updated>2009-12-02T15:31:18.827-08:00</updated><title type='text'>Into The Deep - Deep Copy With PLINQO</title><content type='html'>&lt;p&gt;&lt;br /&gt;There are two reasons for this blog entry. First, I needed a way to replicate some data across databases using Linq To Sql. Second, the good folks at CodeSmith offer a free copy of CodeSmith Professional if you blog your experience with PLINQO. So, in the words of Ricky Ricardo, I got a lot of splainin to do.  &lt;br /&gt;&lt;br /&gt;Oh!, and by the way, please excuse the formatting of the code.  It feels like I spent YEARS trying to get the formatting right on this article.  Just download the code.&lt;br /&gt;&lt;br /&gt;PLINQO is made up of a set of templates for the CodeSmith code generator. These templates allow the generation of several classes that add to the functionality of Linq To Sql. PLINQO is Linq To Sql, only better. You get more functionality, the structure of the project is improved from what you get with Linq To Sql, and PLINQO provides some nifty forward/backward synching of your changes between code and the dbml file. CodeSmith is integrated with Visual Studio, so much of what it does is done right in the good old VS IDE.&lt;br /&gt;&lt;br /&gt;You can find more information, and download CodeSmith and PLINQO at the following sites;&lt;br /&gt;&lt;a title="Code Smith Tools" href="http://www.codesmithtools.com/"&gt;Code Smith Tools&lt;/a&gt;&lt;br /&gt;&lt;a title="PLINQO" href="http://www.plinqo.com/"&gt;PLINQO&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I could go into an exhaustive example of how to setup and use PLINQO here, but I'm going to limit this article to the main reason I'm using PLINQO, which has to do with a glaring problem in Linq To Sql. Specifically, &lt;u&gt;Linq To Sql&lt;/u&gt; doesn't give you an easy way to load a record from one Data Context and write it to another. Once a data entity is attached to the Data Context, it cannot be attached to another, and there is no way to detach it. This makes it rather difficult to copy records from one database to another, or even copy records within the same database.&lt;br /&gt;&lt;br /&gt;The reason that you cant easily move a data entity from one data context to another is because the entity object and the data context are aware of one another through an event model. In other words, when a change is made to an entity's data, an event is fired which the data context handles. This allows the data context to track changes in its attached entities and handle updates quickly and correctly. In order for an entity to be moved to another data context, the event handlers need to be detached. Also, each entity has lists of references to related entities(one to many) and references to other entities (many to one) that must be followed and updated in order for the entity to be used anywhere except attached to its original data context.&lt;br /&gt;&lt;br /&gt;Along comes PLINQO and adds... (drum roll please)... Detach();&lt;br /&gt;&lt;br /&gt;PLINQO's Detach method is implemented in a base class from which all the entities inherit. It navigates down through all linked entities and also detaches them from the data context. All that needs to be done in order to insert these records into another data context is to set any identities to zero, which indicates that this is a new record that needs to be inserted, detach from the current data context, attach the top level entity to a new data context, call SubmitChanges() and BANG! Your records have been inserted into the target database with new identities, which are all wired up correctly.&lt;br /&gt;&lt;br /&gt;As a side note, you should wait to set the primary key to 0 until after you have updated data in any required child entities or you will find the lists of entities to be empty. See the PrepForCopy method in &lt;b&gt;Listing 2&lt;/b&gt; for more details.&lt;br /&gt;&lt;br /&gt;So, let's get down to some code and see if we can make this vague explanation into something more concrete. Again, I am not going into how to setup and use CodeSmith or PLINQO, just the end results and how I used them. For the sake of simplicity I have created a small data model here.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;img title="Database Model" border="0" align="left" src="http://www.webcrafterhosting.com/Portals/0/Plinqodemodb.jpg" /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;b&gt;Figure 1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;This database is pretty simple, with only four tables and three relationships. It also has a unique index on the Code field in the Genre table. This will cause PLINQO to generate a GetByCode method, which you will see later.&lt;br /&gt;Below you will see some code that uses PLINQO, and some home grown code, to select a book from one data context and deep copy it to another.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#000000;"&gt;&lt;b&gt;Listing 1&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Get the book records from the source database.  ddlBooks is a ComboBox control that contains a list of books,&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// with the BookID as the value.&lt;/span&gt;&lt;br /&gt;            Book book = BookExtensions.GetByKey(dc.Book, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)ddlBooks.SelectedValue);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Create a destination data context.&lt;/span&gt;&lt;br /&gt;            PLINQODemoDataContext destDC = &lt;span class="kwrd"&gt;new&lt;/span&gt; PLINQODemoDataContext(PLINQODemo.Properties.Settings.Default.PLINQODemoConnectionString);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Grab the genre from the destination database, by code because the ids may not match.  This demonstrates using the&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// PLINQO Query classes to retrieve a record based on a unique key.&lt;/span&gt;&lt;br /&gt;            Genre destGenre = GenreExtensions.GetByCode(destDC.Genre, book.Genre.Code);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Grab the author from the destination database, by lastname/firstname.  This demonstrates using standard Linq To Sql to&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// retrieve a record.&lt;/span&gt;&lt;br /&gt;            Author destAuthor = (from auths &lt;span class="kwrd"&gt;in&lt;/span&gt; destDC.Author&lt;br /&gt;                                 &lt;span class="kwrd"&gt;where&lt;/span&gt; auths.LastName == book.Author.LastName &amp;amp;&amp;amp;&lt;br /&gt;                                 auths.FirstName == book.Author.FirstName&lt;br /&gt;                                 select auths).Single();&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Set the ids to 0 in book and all sub-entities, so these records will be inserted as new records in the destination.&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// destDC is passed to this method because it is possible to override the ZeroIds method in individual entity classes&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// and do your destination entity lookup, such as genre and author, at that level.&lt;/span&gt;&lt;br /&gt;            book.PrepForCopy(destDC);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// By assigning a new Genre and Author we prevent the insertion of a genre and auther.&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// We are connect the new Book record to an existing Genre and Author in the destination database.&lt;/span&gt;&lt;br /&gt;            book.Genre = destGenre;&lt;br /&gt;            book.Author = destAuthor;&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Detatch book and all sub-entities from source database.&lt;/span&gt;&lt;br /&gt;            book.Detach();&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Update the database.&lt;/span&gt;&lt;br /&gt;            destDC.Book.InsertOnSubmit(book);&lt;br /&gt;            destDC.SubmitChanges();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Look at the third line of code from the bottom. The Detach() method is provided by PLINQO, not by &lt;u&gt;Linq To Sql&lt;/u&gt;. As described above, Detach separates the entity (and all sub-entities) from the data context. However, that is not all we need to do in order to prepare this entity tree to be written to another data context. Since the database has identity columns we must set the identity field to 0 in all entities we want to write out to the new data context, and we must also, prevent some entities from being written, such as lookup tables. In this case, our lookup tables are Genre and Author. In order to prevent new Genre and Author records from being inserted, we grab a copy of the matching Genre and Author entities from the destination database. Notice the PLINQO provided method GenreExtensions.GetByCode(). This allows a very easy way to retrieve a specific Genre record. Since I didn't define a unique index on the LastName and FirstName fields in the Author table, we dont have a handy-dandy method to retrieve that entity, so I use standard Linq To Sql syntax. &lt;i&gt;Yes, I realize that there could be multiple authors with the same name and I haven't accounted for it. This is an example, not a production ready app. &lt;/i&gt;Now I have an entity for Genre and Author, but what do I do with them? Well, we'll get to that in a minute...&lt;br /&gt;&lt;br /&gt;The next line down in the code calls the book.PrefForCopy method. Where did this method come from? Well, that's the home-grown code I mentioned. This is a public virtual method in a brand-spanking new partial class I declared. This partial class adds to the LinqEntityBase class, which is the basis for all of the entity classes. Here's the code for the PrepForCopy method;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#000000;"&gt;&lt;b&gt;Listing 2&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// Zeroes the ids of all related entities, recursively, using polymorphism to ZeroIds on entities with special cases.&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// Each entity with a special case will have a partial calss defined "classname.Extended.cs" to override this behavior.&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="destDataContext"&amp;gt;The dest data context.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PrepForCopy(PLINQODemoDataContext destDataContext)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="rem"&gt;// Using reflection, get the type of the incoming entity, then get all properties for that type.  Then loop through the&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// properties looking for entity sets, which represent lists of sub-entities (table records).&lt;/span&gt;&lt;br /&gt;            Type t = &lt;span class="kwrd"&gt;this&lt;/span&gt;.GetType();&lt;br /&gt;            PropertyInfo[] properties = t.GetProperties();&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PropertyInfo pi &lt;span class="kwrd"&gt;in&lt;/span&gt; properties)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (pi.PropertyType.Name.ToLower().Contains(&lt;span class="str"&gt;"entityset"&lt;/span&gt;))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="kwrd"&gt;object&lt;/span&gt; oEntities = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;br /&gt;                    &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;                    {&lt;br /&gt;                        &lt;span class="rem"&gt;// Get the property value from the property on the provided entity object.&lt;/span&gt;&lt;br /&gt;                        oEntities = pi.GetValue(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;br /&gt;                    }&lt;br /&gt;                    &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)&lt;br /&gt;                    {&lt;br /&gt;                        Exception nex = ex;&lt;br /&gt;                        &lt;span class="kwrd"&gt;throw&lt;/span&gt; ex;&lt;br /&gt;                    }&lt;br /&gt;                    &lt;span class="rem"&gt;// If we got a value from the property, process it as its correct type.&lt;/span&gt;&lt;br /&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (oEntities != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;                    {&lt;br /&gt;                        IList list = (IList)oEntities;&lt;br /&gt;                        &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (LinqEntityBase lbe &lt;span class="kwrd"&gt;in&lt;/span&gt; list)&lt;br /&gt;                        {&lt;br /&gt;                            lbe.PrepForCopy(destDataContext);&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Now zero out the ID fields for this item.  This must be done AFTER the lists of other entities have been processed&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// so that the lists of entities still exist.  Setting IDs to 0 disconnects some of the object model heirarchy.&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (PropertyInfo pi &lt;span class="kwrd"&gt;in&lt;/span&gt; properties)&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="rem"&gt;// Make sure we are dealing with the primary key on the currently processing entity class.&lt;/span&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; ((pi.Name.ToLower().Equals(&lt;span class="kwrd"&gt;this&lt;/span&gt;.GetType().Name.ToLower() + &lt;span class="str"&gt;"id"&lt;/span&gt;)) &amp;amp;&amp;amp; (pi.PropertyType == &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(Int32)))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="rem"&gt;// Set "ID" properties to 0.  This indicates that the record should be inserted as a new record on the next&lt;/span&gt;&lt;br /&gt;                    &lt;span class="rem"&gt;// SubmitChanges call.&lt;/span&gt;&lt;br /&gt;                    pi.SetValue(&lt;span class="kwrd"&gt;this&lt;/span&gt;, 0, &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;        }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This method uses reflection to locate all the entity lists and identity columns and recursively set the proper keys to 0. Hmmm... Doesn't this mean that we just walked down into the Genre and Author tables and set the identity columns to 0, which will cause these records to be inserted as new records in the target database? Good eyes you have there. Yes it does mean that, which brings me back to those two entities we grabbed and held on to up above. Now look at &lt;b&gt;Listing 1&lt;/b&gt;, near the bottom you will see where I assign those entities back into the book entity. Since these already exist in the new data context were good to go. Just call InsertOnSubmit and SubmitChanges and a new book record is inserted. The magic is that the matching Reference records are also replicated.&lt;br /&gt;But, what if I didn't want to copy the references? What if I just wanted the Book record to be copied into the target database? We can handle that in a couple of ways. First you could just;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;book.ReferenceList = null;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;before calling InsertOnSubmit and SubmitChanges, or we could do something a little more creative, using the fact that PrepForCopy is a virtual method on the base class for all the entities... Lets see, if we declare another partial Book class and override the PrepForCopy method, it could look something like this;&lt;br /&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Book&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; PrepForCopy(PLINQODemoDataContext destDC)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="rem"&gt;// Grab the genre from the destination database, by code because the ids may not match.  This demonstrates using the&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// PLINQO Query classes to retrieve a record based on a unique key.&lt;/span&gt;&lt;br /&gt;            Genre destGenre = GenreExtensions.GetByCode(destDC.Genre, &lt;span class="kwrd"&gt;this&lt;/span&gt;.Genre.Code);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Grab the author from the destination database, by lastname/firstname.  This demonstrates using standard Linq To Sql to&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// retrieve a record.&lt;/span&gt;&lt;br /&gt;            Author destAuthor = (from auths &lt;span class="kwrd"&gt;in&lt;/span&gt; destDC.Author&lt;br /&gt;                                 &lt;span class="kwrd"&gt;where&lt;/span&gt; auths.LastName == &lt;span class="kwrd"&gt;this&lt;/span&gt;.Author.LastName &amp;amp;&amp;amp;&lt;br /&gt;                                 auths.FirstName == &lt;span class="kwrd"&gt;this&lt;/span&gt;.Author.FirstName&lt;br /&gt;                                 select auths).Single();&lt;br /&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;base&lt;/span&gt;.PrepForCopy(destDC);&lt;br /&gt;           &lt;br /&gt;            &lt;span class="rem"&gt;//this.ReferenceList = null;&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Genre = destGenre;&lt;br /&gt;            &lt;span class="kwrd"&gt;this&lt;/span&gt;.Author = destAuthor;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Which means that the code from listing 1 can change to simply this;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;color:#000000;"&gt;Listing &lt;span style="font-size:85%;color:#000000;"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Get the book records from the source database.  ddlBooks is a ComboBox control that contains a list of books,&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// with the BookID as the value.&lt;/span&gt;&lt;br /&gt;            Book book = BookExtensions.GetByKey(dc.Book, (&lt;span class="kwrd"&gt;int&lt;/span&gt;)ddlBooks.SelectedValue);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Create a destination data context.&lt;/span&gt;&lt;br /&gt;            PLINQODemoDataContext destDC = &lt;span class="kwrd"&gt;new&lt;/span&gt; PLINQODemoDataContext(PLINQODemo.Properties.Settings.Default.PLINQODemoConnectionString);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Set the ids to 0 in book and all sub-entities, so these records will be inserted as new records in the destination.&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// destDC is passed to this method because it is possible to override the ZeroIds method in individual entity classes&lt;/span&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// and do your destination entity lookup, such as genre and author, at that level.&lt;/span&gt;&lt;br /&gt;            book.PrepForCopy(destDC);&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Detatch book and all sub-entities from source database.&lt;/span&gt;&lt;br /&gt;            book.Detach();&lt;br /&gt;&lt;br /&gt;            &lt;span class="rem"&gt;// Update the database.&lt;/span&gt;&lt;br /&gt;            destDC.Book.InsertOnSubmit(book);&lt;br /&gt;            destDC.SubmitChanges();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Either way will work. The second way may not be as flexible if you are planning to use the data model for copying records in multiple ways. However, using the second method I was able to generate my PLINQO classes, override the PrepForCopy method on for certain classes, and deep copy database records from a data model with 44 interconnected tables. I had to make some special arrangements for some of the tables where foreign key relationships were missing from the database, but all in all, this was much easier than if I had to do the same thing using DataSets and DataTables, handling the primary and foreign key values myself.&lt;br /&gt;&lt;br /&gt;There were some things about PLINQO that I thought could be improved. Thats what new versions are all about, right? One thing I noticed hasto do with regeneration of the dbml file. The database I was trying to use was already being used in a production environment and could not be changed. It was also missing some relationships between some of the tables, which caused some code generation problems. I assumed I could add those relationships in the dbml editor and have those changes be persisted down into the generated code. However, my changes were overwritten the next time I compiled. I found a reference to this in a forum, where the folks at Code Smith Tools indicate that they already know about this and are considering adding this ability for a future release.&lt;br /&gt;&lt;br /&gt;Overall, I am impressed with PLINQO, and I will be using PLINQO in the future.&lt;br /&gt;&lt;br /&gt;Code for this project can be downloaded at; &lt;a title="PLINQODemo.zip" href="http://www.webcrafterstudio.com/Portals/0/PLINQODemo.zip"&gt;PLINQO Demo&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-5192576295245984693?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/5192576295245984693/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2009/11/there-are-two-reasons-for-this-blog.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/5192576295245984693'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/5192576295245984693'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2009/11/there-are-two-reasons-for-this-blog.html' title='Into The Deep - Deep Copy With PLINQO'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-4512782294412136255</id><published>2009-03-28T16:56:00.000-07:00</published><updated>2009-03-28T18:17:49.683-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='2009'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='BlackBerry'/><title type='text'>Charlotte Code Camp Spring 2009 - An Amazing  Experience!</title><content type='html'>Code Camp was absolutely incredible! We had a great turn out. I had a great time, learned some stuff, taught some stuff, and generally enjoyed the entire experience. I had the honor of attending the "How to Start Writing Your Own Games on &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;XNA&lt;/span&gt;" Lab, taught by Alberto &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Botero&lt;/span&gt;. As, someone who has written games the hard way, I was blown away with how easy it was to get really nice results.&lt;br /&gt;&lt;br /&gt;A couple of our presenters didn't make it to code camp, one because he was involved in a car accident. So, we found ourselves with a full classroom and no presenter. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Farhad&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;Javidi&lt;/span&gt; stepped in to keep the crowd entertained while we scrambled to figure out what to do. I offered to do "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;BlackBerry&lt;/span&gt; Jam for Beginners" early, and was a little surprised when the folks, who were gathered for an iPhone presentation, took me up on it. Since we got a late start, I ran long and wasn't able to spend enough time on web services, stub generation, or threading. I hope the folks who attended will &lt;a href="http://www.webcrafterstudio.com/portals/0/BlackBerryJamForBeginners.zip"&gt;download&lt;/a&gt; the sample code and slides, which I think contain enough information to explain what must be done when calling web services.&lt;br /&gt;&lt;br /&gt;My second session, in my scheduled time slot, went much, much better. I had time to get through everything, and there were some really good questions. Some people, who attended the first session, returned for the second session, which I was very glad to see. It gave me a chance to redeem myself a bit. I hope everyone enjoyed it, I know I did.&lt;br /&gt;&lt;br /&gt;Bill Bird attended both sessions and had some additional insights to offer. He suggested that we form some sort of Charlotte area &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;BlackBerry&lt;/span&gt; developer's group. I suggested that for now we could put together a discussion forum on a website. If I get time I'll look into doing that.&lt;br /&gt;&lt;br /&gt;Many thanks to everyone who chose to attend my sessions, I really appreciate the support.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-4512782294412136255?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/4512782294412136255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2009/03/charlotte-code-camp-spring-2009-amazing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4512782294412136255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4512782294412136255'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2009/03/charlotte-code-camp-spring-2009-amazing.html' title='Charlotte Code Camp Spring 2009 - An Amazing  Experience!'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-8293305629834378593</id><published>2009-03-26T17:49:00.000-07:00</published><updated>2009-03-26T19:10:58.120-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CLDC'/><category scheme='http://www.blogger.com/atom/ns#' term='JSR-172'/><category scheme='http://www.blogger.com/atom/ns#' term='webservice'/><category scheme='http://www.blogger.com/atom/ns#' term='Web Service'/><category scheme='http://www.blogger.com/atom/ns#' term='BlackBerry JDE'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='BlackBerry'/><title type='text'>BlackBerry Jam for Beginners</title><content type='html'>Over the past several weeks I have been teaching myself &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;BlackBerry&lt;/span&gt; development. I'm doing this for two reasons. First, I volunteered myself to present at Microsoft Code Camp, which I mentioned in an earlier blog entry. Second, I believe there is money to be made in the world of mobile applications. I have an idea that I would like to develop into an application for sale to the general public. Volunteering to present at Code Camp forced me to spend the time it took to learn this new set of skills.&lt;br /&gt;&lt;br /&gt;Knowing absolutely nothing about Java or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;BlackBerry&lt;/span&gt; made my journey into the world of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;BlackBerry&lt;/span&gt; development quite a challenge. After some initial investigation I discovered that there were two different platforms for developing BB applications. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;MDS&lt;/span&gt; (Mobile Data System) applications, which require the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;BlackBerry&lt;/span&gt; Enterprise Server (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;BES&lt;/span&gt;), and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;CLDC&lt;/span&gt;/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;MIDP&lt;/span&gt; applications. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;MDS&lt;/span&gt; applications appear to be easier to design and write, based on information I have read on the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;BlackBerry&lt;/span&gt; site. However, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;BES&lt;/span&gt; is expensive and not available to your everyday BB user. So &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;CLDC&lt;/span&gt;/&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;MIDP&lt;/span&gt; was my only choice.&lt;br /&gt;&lt;br /&gt;After more investigation I discovered that there is more than one development environment for creating &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;CLDC&lt;/span&gt; applications. RIM provides the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;BlackBerry&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;JDE&lt;/span&gt; and also a plug-in for Eclipse, which seems to be very popular among Java &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_16"&gt;developers&lt;/span&gt;. I did some reading on various Blogs and forums and discovered that, although Eclipse is very popular, it does provide some additional challenges, especially around debugging and use of simulators. I really wanted to keep my learning curve to a minimum, so I chose to use the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;BlackBerry&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;JDE&lt;/span&gt;, even though Eclipse may have provided some very nice editing features.&lt;br /&gt;&lt;br /&gt;One of my main goals was to be able to call web services from the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;BlackBerry&lt;/span&gt;. For the application I intend to build, eventually, it will be required, so I decided to make that the goal for my Code Camp presentation. After many long hours of investigation, and many false leads, I discovered that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;JSR&lt;/span&gt;-172 had been implemented in the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;BlackBerry&lt;/span&gt; OS beginning with version 4.3. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;JSR&lt;/span&gt;-172 is a Java standard for accessing web services. I also found an Open Source project called K-SOAP. K-SOAP was built as a way call web services before &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;JSR&lt;/span&gt;-172 had been implemented. K-SOAP 2 is supposed to be much easier to use than the original version and also easier than &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;JSR&lt;/span&gt;-172. However, since I own a Curve with OS version 4.3 I decided to keep it "all in the family" and go with the built-in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;JSR&lt;/span&gt;-172 implementation.&lt;br /&gt;&lt;br /&gt;I have built three sample applications, which demonstrate various facets of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;BlackBerry&lt;/span&gt; development. These are not intended to be an exhaustive demonstration of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;BlackBerry&lt;/span&gt; capabilities, but just to break the ice for those folks out there who are in the same boat I was, with little to no experience on this platform. The first example is a pretty simple application that just shows the basic layout of a BB Java app. The second example, shows how to incorporate localization through the use of resource files. Still, not a big jump ahead, but most mobile applications sold to the general public are sold on websites, which are available anywhere in the world, so... localization may eventually be needed. Also, by using resource files, you gain the ability to set the application title, which is displayed on the BB desktop. The third example makes a pretty big jump, since it incorporates both web service calls, via &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;JSR&lt;/span&gt;-172, and also some simple threading. It turns out that threading is required because you can't call a web service using the same thread the processes events for your application. It really makes sense if you think about it, but it was a bit of a surprise when I first ran into it. Also, this is a good place to point out that it works fine without threading when using the simulator. The simulator also allows applications to run without code signing, where certain restricted &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;APIs&lt;/span&gt; can only be used, on a real device, after the code is signed. Signing is also required, on a real device, in order to avoid warning messages to users when trying to call web services, something I didn't discover until after I had deployed the application to my Curve.&lt;br /&gt;&lt;br /&gt;I'm a big &lt;a href="http://www.supercross.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;SuperCross&lt;/span&gt;&lt;/a&gt; fan, and a play-school level, non-&lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_31"&gt;competitive&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;Moto&lt;/span&gt;-X rider.  So, my sample code may seem a little unusual.  No &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;Northwind&lt;/span&gt; or Pubs database here.  This calls a web service that provides the ability to &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_34"&gt;look up&lt;/span&gt; a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;SuperCross&lt;/span&gt; rider by his number.  It isn't very sophisticated and the data returned is minimal, but I think it is a good demonstration of the techniques required for mobile applications, and its more fun that &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;Northwind&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;I have uploaded my presentation slides and my sample code to my company site.  Here's a link to the &lt;a href="http://www.webcrafterstudio.com/portals/0/BlackBerryJamForBeginners.zip"&gt;zip file&lt;/a&gt;. I have left the web service running, so anyone who downloads the sample code can see it run.   Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-8293305629834378593?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/8293305629834378593/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2009/03/blackberry-jam-for-beginners.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/8293305629834378593'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/8293305629834378593'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2009/03/blackberry-jam-for-beginners.html' title='BlackBerry Jam for Beginners'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-7029300515829205852</id><published>2009-03-21T20:46:00.000-07:00</published><updated>2009-03-21T21:09:12.031-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Web Service'/><category scheme='http://www.blogger.com/atom/ns#' term='Enterprise Developer&apos;s Guild'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Camp'/><category scheme='http://www.blogger.com/atom/ns#' term='BlackBerry'/><title type='text'>BlackBerry Jam @ Charlotte Code Camp</title><content type='html'>On March 28th I will be speaking at a Microsoft Code Camp hosted by The Charlotte Area Enterprise Developer's Guild at Central Piedmont Community College.  My presentation will be called "BlackBerry Jam for Beginners" and will provide some much needed information for programmers who would like to build applications for BlackBerry.  When I decided to do this presentation I knew absolutely nothing about BlackBerry or Java.  Finding resources was difficult to say the least.  There are no books, that I could find, that explain how to build BlackBerry applications, and information found via Google was spotty  and required many, many hours to locate and sift.  The presentation will introduce students to the tools required to build applications for BlackBerry and will also involve a sample application, which calls a web service to retrieve data.  I plan to blog this presentation as soon as I have time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-7029300515829205852?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/7029300515829205852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2009/03/blackberry-jam-charlotte-code-camp.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/7029300515829205852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/7029300515829205852'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2009/03/blackberry-jam-charlotte-code-camp.html' title='BlackBerry Jam @ Charlotte Code Camp'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1234990956553167879.post-4503781250849245268</id><published>2009-03-21T20:40:00.000-07:00</published><updated>2009-03-21T20:43:35.188-07:00</updated><title type='text'>Well, here I go...</title><content type='html'>People have been telling me for the last couple of years that I need a blog.  I lead a very busy life, with my family, church, and professional commitments and really never thought I would have time for a blog.  However, I think the time has come, so here I go...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1234990956553167879-4503781250849245268?l=martinturner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://martinturner.blogspot.com/feeds/4503781250849245268/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://martinturner.blogspot.com/2009/03/well-here-i-go.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4503781250849245268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1234990956553167879/posts/default/4503781250849245268'/><link rel='alternate' type='text/html' href='http://martinturner.blogspot.com/2009/03/well-here-i-go.html' title='Well, here I go...'/><author><name>Marty</name><uri>http://www.blogger.com/profile/12595791062704774155</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
