Any WCF/LINQ experts out there?  I'm having a heck of a time getting my relational data to pass through WCF.

First off, I tried all of this through straight LINQ to SQL and was getting some error regarding a circular reference, which I found puzzling as I didn't see a circular reference in my db.  After fighting with LINQ to SQL I moved on to trying PLINQO and the circular error went away, however the nested Lists of entities won't transmit properly.

I have several tables in my db but the 2 currently in question are CustomersVendors and Addresses.  The addresses are linked to the CustomersVendors table via listID <--- customerVendorListID and the 2 columns are identical.  When I request a CustomerVendor by listID I expect to get back all of their details including a List(Of Addresses).  Upon tracing the results I see the query works just fine and I do in fact see the Addresses in the CustomersVendors entity.  The problem is, once this data is sent out via WCF the Addresses entity inside of the CustomerVendor is NULL.  Tracelogs on the server side of my app don't show the addresses so they are obviously never leaving the server.  I'm guessing it's a serialization issue but I'm at the end of my rope trying to find the cause.  I sure hope someone out there can figure this one out.

vs2008 SP1 (VB.NET)
.NET 3.5 SP1
Vista Business SP3
PLINQO v3.0.687
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Fernando SotoRetiredCommented:
Hi thesnoman;

I am not a WCF expert but you seem to be on the right track about serialization. Linq by default sets the Serialization Mode to none. In WCF applications it should be set to Unidirectional which will allow the child records to come across as well. To set the DataContext for this setting do the following.

1. Open the OR/M designer and right click on the design surface where there are NO tables.
2. Select Properties in the context menu.
3. Select the Serialization Mode property and in its combo box select Unidirectional.

Hopefully this will do it.

thesnomanAuthor Commented:
Thanks for the reply Fernando,

I've actually tried that and it didn't help.  I've not found a true solution yet so for now what I've done is remove all relationships from the db and create wrappers for sending the data, as shown in the code snippet.  This works fine but it adds a fair amount of code and time to parse.  I'm not yet sure what I'm going to run into for saving but I'm sure it's going to be a lot more work.  It's a shame when something that's supposed to save us time costs us a lot more.  If you or anyone else has anymore ideas please pass them along as I'd be glad to hear them.

Custom Wrapper:
<DataContract()> _
Public Class twCustomerVendor
    Private _customerVendor As CustomersVendor
    Private _addresses As List(Of Address)
    Private _contacts As List(Of Contact)
    <DataMember()> _
    Public Property CustomerVendor() As CustomersVendor
            Return Me._customerVendor
        End Get
        Set(ByVal value As CustomersVendor)
            Me._customerVendor = value
        End Set
    End Property
    <DataMember()> _
Public Property Addresses() As List(Of Address)
            Return Me._addresses
        End Get
        Set(ByVal value As List(Of Address))
            Me._addresses = value
        End Set
    End Property
    <DataMember()> _
Public Property Contacts() As List(Of Contact)
            Return Me._contacts
        End Get
        Set(ByVal value As List(Of Contact))
            Me._contacts = value
        End Set
    End Property
End Class
Then I populate it as follows:
Public Function GetCustomerVendor(ByVal ListID As Integer) As twCustomerVendor
    Dim Context As New OxionIt2DataContext
    Dim ret As New twCustomerVendor
    ret.CustomerVendor = (From cv In Context.CustomersVendor _
                          Where cv.ListID = ListID _
                          Select cv).SingleOrDefault
    ret.Addresses = (From a In Context.Address _
                     Where a.CustomerVendorListID = ret.CustomerVendor.ListID _
                     Select a).ToList
    ret.Contacts = (From c In Context.Contact _
                    Where c.CustomerVendorListID = ret.CustomerVendor.ListID _
                    Select c).ToList
    Return ret
End Function

Open in new window

thesnomanAuthor Commented:
For future reference I found the solution.  It is not a WCF serialization issue as first suspected rather it part of LINQ's lazy loading technique.  While I knew this existed I did not know that at the time of loading the parent it does not actually load all the related children as I would have expected.  There is a way to get around this issue and it involves LINQ's "DataLoadOptions" command.  This forces LINQ to load all the related info when the parent record is loaded.  This can also be a good thing to minimize the number of queries made against the database.  

Here is a sample of my code in VB that may save someone else hours/days of research, troubleshooting, and heartache.  Notice DataLoadOptions and each line specifying LoadWith with a regular expression enclosed (something I don't know much about) identifying each child (related table) object to load.  Obvioiusly, depending on what data you wanted to load at the time you could include a limited number of children but in my case I wanted all relational data to be populated and sent to the WCF client for viewing/editing.
Hope this helps someone else out.

P.S. For what it's worth, I am using the PLINQO templates as mentioned earlier to setup, maintain and extend my LINQ entities and the dbml file and sp far I like it.  If you are interested in it you can do a Google search PLINQO and CodeSmith, the application that actually runs it.  One very nice feature, when you change your database schema you can actually refresh the dbml file and entities by regenerating the PLINQO output.  So far this has saved me a lot of time and it sets up a very clean project.

        Public Function GetCustomerVendor(ByVal ListID As Integer) As CommWrapper
            Dim Context As New DataContext
            Dim ret As New CommWrapper
            Dim dlOptions = New DataLoadOptions()
            ' Causes the Customer/Vendor to actively load the related data lists.  One required for each relational table.
            dlOptions.LoadWith(Of CustomersVendor)(Function(cv) cv.CustomerVendorAddressList)
            dlOptions.LoadWith(Of CustomersVendor)(Function(cv) cv.CustomerVendorCommissionList)
            dlOptions.LoadWith(Of CustomersVendor)(Function(cv) cv.CustomerVendorContactList)
            dlOptions.LoadWith(Of CustomersVendor)(Function(cv) cv.CustomerVendorEmailAddressList)
            dlOptions.LoadWith(Of CustomersVendor)(Function(cv) cv.CustomerVendorPhoneNumberList)
            Context.LoadOptions = dlOptions
            ret.CustomerVendorList = (From cv In Context.CustomersVendor _
                                  Where cv.ListID = ListID _
                                  Select cv).ToList
            Return ret
        End Function

Open in new window


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.