Solved

LINQ/PLINQO/WCF Nightmare

Posted on 2009-07-11
3
851 Views
Last Modified: 2013-11-11
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
0
Comment
Question by:thesnoman
  • 2
3 Comments
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 24830397
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.

Fernando
0
 

Author Comment

by:thesnoman
ID: 24830985
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
        Get
            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)
        Get
            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)
        Get
            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

0
 

Accepted Solution

by:
thesnoman earned 0 total points
ID: 24835817
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

0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…
This lesson covers basic error handling code in Microsoft Excel using VBA. This is the first lesson in a 3-part series that uses code to loop through an Excel spreadsheet in VBA and then fix errors, taking advantage of error handling code. This l…

685 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question