Solved

LINQ/PLINQO/WCF Nightmare

Posted on 2009-07-11
3
841 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 62

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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Suggested Solutions

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

762 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

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now