views:

286

answers:

0

I have been developing a Silverlight WCF RIA Services application dealing with mock financial transactions. To more efficiently send summary data to the client without going overboard with serialized entities I have created a summary class that isn’t in my EDM, and figured out how to serialize and send it over the wire to the SL client using DataContract() and DataMember(). Everything seemed to be working out great, until I tried to bind controls to a list inside my custom object. The list seems to always get deserialized with an extra, almost empty entity in it that I don’t know how to get rid of. So, here are some of the pieces. First the relevant bits from the custom object class:

<DataContract()> _
Public Class EconomicsSummary

    Public Sub New()
        RecentTransactions = New List(Of Transaction)
        TotalAccountHistory = New List(Of Transaction)
    End Sub

    Public Sub New(ByVal enUser As EntityUser)
        Me.UserId = enUser.UserId
        Me.UserName = enUser.UserName
        Me.Accounts = enUser.Accounts
        Me.Jobs = enUser.Jobs

        RecentTransactions = New List(Of Transaction)
        TotalAccountHistory = New List(Of Transaction)
    End Sub

    <DataMember()> _
    <Key()> _
    Public Property UserId As System.Guid

    <DataMember()> _
    Public Property NumTransactions As Integer

    <DataMember()> _
    <Include()> _
    <Association("Summary_RecentTransactions", "UserId", "User_UserId")> _
    Public Property RecentTransactions As List(Of Transaction)

    <DataMember()> _
    <Include()> _
    <Association("Summary_TotalAccountHistory", "UserId", "User_UserId")> _
    Public Property TotalAccountHistory As List(Of Transaction)

End Class

Next, the relevant parts of the function called to return the object:

Public Function GetEconomicsSummary(ByVal guidUserId As System.Guid) As EconomicsSummary
        Dim objOutput As New EconomicsSummary(enUser)
        For Each objTransaction As Transaction In (From t As Transaction In Me.ObjectContext.Transactions.Include("Account") Where t.Account.aspnet_User_UserId = guidUserId Select t Order By t.TransactionDate Descending Take 10)
            objTransaction.User_UserId = objOutput.UserId
            objOutput.RecentTransactions.Add(objTransaction)
        Next
        objOutput.NumTransactions = objOutput.RecentTransactions.Count

…

        Return objOutput
    End Function

Notice that I’m collecting the NumTransactions count before serialization. Should be 10 right? It is – BEFORE serialization. The DataGrid is bound to the data source as follows:

<sdk:DataGrid AutoGenerateColumns="False" Height="100" MaxWidth="{Binding ElementName=aciSummary, Path=ActualWidth}" 
                    ItemsSource="{Binding Source={StaticResource EconomicsSummaryRecentTransactionsViewSource}, Mode=OneWay}" 
                    Name="gridRecentTransactions" RowDetailsVisibilityMode="VisibleWhenSelected" IsReadOnly="True">
    <sdk:DataGrid.Columns>
        <sdk:DataGridTextColumn x:Name="TransactionDateColumn" Binding="{Binding Path=TransactionDate, StringFormat=\{0:d\}}" Header="Date" Width="SizeToHeader" />
        <sdk:DataGridTextColumn x:Name="AccountNameColumn" Binding="{Binding Path=Account.Title}" Header="Account" Width="SizeToCells" />
        <sdk:DataGridTextColumn x:Name="CurrencyAmountColumn" Binding="{Binding Path=CurrencyAmount, StringFormat=\{0:c\}}" Header="Amount" Width="SizeToHeader" />
        <sdk:DataGridTextColumn x:Name="TitleColumn" Binding="{Binding Path=Title}" Header="Description" Width="SizeToCells" />
        <sdk:DataGridTextColumn x:Name="ItemQuantityColumn" Binding="{Binding Path=ItemQuantity}" Header="Qty" Width="SizeToHeader" />
    </sdk:DataGrid.Columns>
</sdk:DataGrid>

You might be wondering where the ItemsSource is coming from, that looks like this:

<CollectionViewSource x:Key="EconomicsSummaryRecentTransactionsViewSource" Source="{Binding Path=DataView.RecentTransactions, ElementName=EconomicsSummaryDomainDataSource}" />

When I noticed that the DataGrid had the extra row I tried outputting some data after the data source finishes loading, as follows:

Private Sub EconomicsSummaryDomainDataSource_LoadedData(ByVal sender As System.Object, ByVal e As System.Windows.Controls.LoadedDataEventArgs) Handles EconomicsSummaryDomainDataSource.LoadedData

    If e.HasError Then
        System.Windows.MessageBox.Show(e.Error.ToString, "Load Error", System.Windows.MessageBoxButton.OK)
        e.MarkErrorAsHandled()
    End If

    Dim objSummary As EconomicsSummary = CType(EconomicsSummaryDomainDataSource.Data(0), EconomicsSummary)
    Dim sb As New StringBuilder("")

    sb.AppendLine(String.Format("Num Transactions: {0} ({1})", objSummary.RecentTransactions.Count.ToString(), objSummary.NumTransactions.ToString()))
    For Each objTransaction As Transaction In objSummary.RecentTransactions
        sb.AppendLine(String.Format("Recent TransactionId {0} dated {1} CurrencyAmount {2} NewBalance {3}", objTransaction.TransactionId.ToString, objTransaction.TransactionDate.ToString("d"), objTransaction.CurrencyAmount.ToString("c"), objTransaction.NewBalance.ToString("c")))
    Next
    txtDebug.Text = sb.ToString()

End Sub

Output from that looks like this:

Num Transactions: 11 (10)
Recent TransactionId 2283 dated 6/1/2010 CurrencyAmount $31.00 NewBalance $392.00
Recent TransactionId 2281 dated 5/31/2010 CurrencyAmount $33.00 NewBalance $361.00
Recent TransactionId 2279 dated 5/28/2010 CurrencyAmount $8.00 NewBalance $328.00
Recent TransactionId 2277 dated 5/26/2010 CurrencyAmount $22.00 NewBalance $320.00
Recent TransactionId 2275 dated 5/24/2010 CurrencyAmount $5.00 NewBalance $298.00
Recent TransactionId 2273 dated 5/21/2010 CurrencyAmount $19.00 NewBalance $293.00
Recent TransactionId 2271 dated 5/20/2010 CurrencyAmount $20.00 NewBalance $274.00
Recent TransactionId 2269 dated 5/19/2010 CurrencyAmount $48.00 NewBalance $254.00
Recent TransactionId 2267 dated 5/18/2010 CurrencyAmount $42.00 NewBalance $206.00
Recent TransactionId 2265 dated 5/14/2010 CurrencyAmount $5.00 NewBalance $164.00
Recent TransactionId 0 dated 6/1/2010 CurrencyAmount $0.00 NewBalance $361.00

So I have a few different questions:

-First and foremost, where the devil is that extra Transaction entity coming from and how do I get rid of it? Does it have anything to do with the other list of Transaction entities being serialized as part of the EconomicsSummary class (TotalAccountHistory)? Do I need to decorate the EconomicsSummary class members a little more/differently?

-Second, where are the peculiar values coming from on that extra entity?

PRE-POSTING UPDATE 1: I did a little checking, it looks like that last entry is the first one in the TotalAccountHistory list. Do I need to do something with CollectionDataContract()?

PRE-POSTING UPDATE 2: I fixed one bug in TotalAccountHistory, since the objects weren’t coming from the database their keys weren’t unique. So I set the keys on the Transaction entities inside TotalAccountHistory to be unique and guess what? Now, after deserialization RecentTransactions contains all its original items, plus every item in TotalAccountHistory. I’m pretty sure this has to do with the deserializer getting confused by two collections of the same type. But I don’t yet know how to resolve it…