CodeTrigger  

Code Generation For C#, WPF, WCF, SQL SERVER/ORACLE/MYSQL and Visual Studio 2013-2019

Tutorial - Saving Objects and Child Collections Over WCF with CodeTrigger
The default samples generated by CodeTrigger mostly deliver shallow saving of objects. If you encounter a scenario where you need to save a deep/nested collection of objects from the client over the WCF boundary, the following guide shows how you can go about it.
This guide has been updated for version 5.1.0.0 (released June 10th 2017)

STEP 1 - Ensure you have a relevant test database

This tutorial is taken from a real world exercise, where the established database schema was as follows:

A 'Project' Table (with identity Id column)
    ---- A 'Provenance' table (with identity Id column). This table contains a foreign key reference to the Project table. ie. the Project has a collection of zero or more Provenance entities.
        ---- A 'WorkDetails' table (with identity Id column). This table contains a foreign key reference to the Provenance table. ie each Provenance has a collection of zero or more WorkDetail entities.

The requirement is to save a 'Project' plus its 2 nested layers of child entities, from a WPF client, over the WCF boundary, to the server/db

Step 2 - Create a new CodeTrigger project

From the Visual Studio 'Tools' menu (or from Enterprise Architect's 'Extensions' menu)...

Open CodeTrigger
Select 'New' (or '+' icon)
Solution Name = CodeTriggerDeepSaveWcfSample
Location = C:\CodeTriggerSamples
As your Codetrigger Solution settings.

Select the 'DB to Multi-tier Wcf application' wizard
Click Next
Name your new CodeTrigger project 'ObjectGraph'
Ensure that 'Include ObjectGraph.Wpf' is ticked.

Click Next on the Wizard to setup the data source. Click 'Connect' to validate the data source.

Step 3 - Configure and Generate code

Configure datasource
Create project
Ensure 'Enable for Unit of Work pattern': Ticked
Select the related nested tables in the Schema Objects tab (For this tutorial this is 'Project', Provenance', 'WorkDetails')
Select the objects in the Business Objects tab. Be sure to expand the object and select the 'Entity Collection' child item so that collection management code is generated.
Generate the code.

Step 4 - Extend your generated business object classes

Add a folder called 'Extensions' to the ObjectGraph.Business project
Add the following partial class extensions to the Extensions folder:
                    
/*ObjectGraph.Business/Extensions/BOProject.cs*/
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
 
namespace ObjectGraph.Business
{
    public partial class BOProject
    {
        [DataMember]
        public virtual IList<BOProvenance> Provenances
        {
            get
            {
                if (_boProvenanceCollection == null)
                    LoadProvenanceCollection();
                return _boProvenanceCollection != null ? 
                    _boProvenanceCollection.ToList() : null;
            }
            set { _boProvenanceCollection = value != null ? 
                value.ToList<BOProvenance>() : null; }
        }
    }
}
 
 
/*ObjectGraph.Business/Extensions/BOProvenance.cs*/
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
 
namespace ObjectGraph.Business
{
    public partial class BOProvenance
    {
        [DataMember]
        public virtual IList<BOWorkDetails> WorkDetails
        {
            get
            {
                if (_boWorkDetailsCollection == null)
                    LoadWorkDetailsCollection();
                return _boWorkDetailsCollection != null ? 
                    _boWorkDetailsCollection.ToList() : null;
            }
            set
            { _boWorkDetailsCollection = value != null ? 
                    value.ToList<BOWorkDetails>() : null; 
            }
        }
    }
}
                    
                

Step 5 - Add UnitOfWork Implementation

Copy the IUnitOfWork.cs and UnitOfWorkImp.cs classes as defined in the UnitOfWork tutorial here to your ObjectGraph.Business/Implementation folder.
Fix the namespace(s) to match your correct project namespace.

Step 5 - Extend the WCF service interface and service

Add an Extensions folder to the Wcf project and add class extension to the WCF service to deep save the object, with transaction and rollback
                    
/*ObjectGraph.Wcf/Extensions/ObjectGraphService.svc.cs*/
using System;
using System.ServiceModel;
using ObjectGraph.Business;
 
namespace ObjectGraph.Wcf
{
    public partial interface IBOProjectSvc
    {
        [OperationContract]
        void DeepSaveNewProject(BOProject project);
    }
 
    public partial class ObjectGraphService
    {
        public virtual void DeepSaveNewProject(BOProject project)
        {
            IUnitOfWork uow = new UnitOfWorkImp();
            uow.Create(project);
 
            foreach (var provenance in project.Provenances)
            {
                var provenance1 = provenance;
                uow.Create(new UnitOfWorkForwarder((Action)delegate 
                        { provenance1.ProjectID = project.Id; }, 
                        null, null));
                uow.Create(provenance);
                foreach (var work in provenance.WorkDetails)
                {
                    var work1 = work;
                    var provenance2 = provenance;
                    uow.Create(new UnitOfWorkForwarder((Action)delegate 
                        { work1.ProvenanceID = provenance2.Id; }, 
                        null, null));
                    uow.Create(work);
                }
            }
            string errMsg;
            if (!uow.Commit(out errMsg)) 
            { throw new Exception("Error while deep saving project: " + errMsg); }
        }
    }
}
                    
                

Step 6 - Rebuild and reconfigure WCF service

Rebuild the WCF service
Reconfigure the ObjectGraph.Wpf Service Reference to use Array List

Step 7 - Modify and Test your Deep Saving Wpf/Wcf App

Add a button anywhere on your WPF forms project, with a click handler, and test deep save functionality with the code:
                       
void saveBtn_Click(object sender, RoutedEventArgs e)
{
    BOProject newProject = new BOProject();
    newProject.Name = "My New Project100";
 
    newProject.Provenances = new BOProvenance[]
    {
        new BOProvenance()
        {
            Name = "First New Provenance",
            Comments = "This is a comment",
            WorkDetails = new BOWorkDetails[]
            {
                new BOWorkDetails() { Name = "First New Work Detail", 
                    TaskDetails = "First task details" },
                new BOWorkDetails() { Name = "Second New Work Detail", 
                    TaskDetails = "Second task details" },
            }
        },
        new BOProvenance()
        {
            Name = "Second New Provenance",
            Comments = "This is a comment",
            WorkDetails = new BOWorkDetails[]
            {
                new BOWorkDetails() { Name = "Third New Work Detail", 
                    TaskDetails = "Third task details" },
                new BOWorkDetails() { Name = "Fourth New Work Detail", 
                    TaskDetails = "Fourth task details" },
            }
        }
    };
 
    ObjectGraphServiceClient svc = new ObjectGraphServiceClient();
    try
    {
        svc.DeepSaveNewProject(newProject);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        if (svc.State == System.ServiceModel.CommunicationState.Faulted) 
        svc.Abort();
        else 
        svc.Close();
    }
}