Link to home
Start Free TrialLog in
Avatar of darbid73
darbid73Flag for Germany

asked on

Serialize LINQ to SQL

I get a very long strange error when I try to serialize this.

On this line
ser.WriteObject(stream1, casenames)

Open in new window


 I assume it is because I have a select in there and thus not the full table.  

I am using LINQ to SQL and have the DataMember DataContract attributed decorating my Entity Classes.

Dim db As New DataClasses1DataContext

        Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select cn.Kan, cn.Sach, cn.LuT).First


        Dim stream1 As New MemoryStream()
        Dim ser As New DataContractJsonSerializer(GetType(tbl_test))
        ser.WriteObject(stream1, casenames)
        Debug.Print(Encoding.UTF8.GetString(stream1.ToArray()))

Open in new window


Could someone please help.
Avatar of Jesse Houwing
Jesse Houwing
Flag of Netherlands image

See: http://stackoverflow.com/questions/2307173/passing-an-instance-of-anonymous-type-over-wcf

The short answer is: Don't, just return a real type (either the table, or a separate class you've created specifically for this scenario).

The long answer is: It is possible, but not by default.
Avatar of darbid73

ASKER

Ok let me understand the problem.

My object t(hat is the table) has the attributes decorated, but this will only work if I try to serialize whole table.  If i start picking pieces out then it is going to fail.

My choices are

1. Create now my own classes for each individual query that I might possibly use and then refer to them in serialization
2. Return the whole table and then just get the parts that I want. (seems like a waste but if the table is not too big then ok)

or

can I decorate these fields with something to identify that I might just want them.
ASKER CERTIFIED SOLUTION
Avatar of Jesse Houwing
Jesse Houwing
Flag of Netherlands image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Great thanks.

So right now LINQ to SQL wrote all my Entity classes for me and I imagine updates them if the tables change.  I just had to change the Serialization to undirectional, so that the decorations were added.

So I now have to write my own decorated classes for any special queries I want to do, then I have to maintain them and change them if I update anything with respect to them.

Is this the right direction?
You're doing great :)
You might want to check out Entity Framework though, Linq-2-SQL isn't going to evolve any further in the near future and Microsoft has shifted all its resources to Entity Framework.

Release 4.1 is almost ready (RC stage, with GoLive license) and it supports Code first development. That way you just specify your classes and EF will do the dataaccess for them (without any ugly code inside your classes).

http://thedatafarm.com/blog/data-access/new-ef4-amp-ef4-1-content-on-msdn/
I don't see the error that you are getting, so you should address that, to determine the best course of action.  Entity Framework has its own set of problems, when it comes to JSON serialization, so it wouldn't be a panacea.
Entity Framework 4.1 Code First solves a lot of the JSon issues, as it allows you to use plain object classes.
I don't see the error that you are getting, so you should address that,
Hi T.L.O.

If I hover my mouse over "casenames" like it is now it will something with the word "anonymous" in it.  If I take off the select then it will show the table "tbl_test".

But the error message is massive and does not make any sense to me.

Actually in the link above to stackoverflow this message here is similar i think - although this is the second part there is a lot more

Type '<>f__AnonymousType0`2[System.String,System.String]' cannot be serialized.
Consider marking it with the DataContractAttribute attribute, and marking all
of its members you want serialized with the DataMemberAttribute attribute.  
See the Microsoft .NET Framework documentation for other supported types.

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Yes, this is what we decided on before:

1. Create now my own classes for each individual query that I might possibly use and then refer to them in serialization

I was distracted by the talk of Entity Framework, and other such discussions, and missed that one line in the author's comment...
Ok I hope I am up with you guys.  I think you are showing me what I want to do, just I might need to know the right steps.

So I have now created a new class decorated with datacontract / datamembers and the class only has 3 properties to match my select.

Now I only know how to do this the long way, eg

Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select cn.Kan, cn.Sach, cn.LuT).tolist

Dim res As New List(Of c_Special)

        For Each cn In casenames

            res.Add(New c_Special(cn.Kan, cn.Sach, cn.LuT))

        Next

Open in new window

Then I can serialize c_Special.

So I think TLO you are trying to get me to do this in one step?

You can do the select into a List(Of class) in one step, but if you feel comfortable with your results (small data sets), then I would go with your process.  If you have large datasets, then that extra For loop step is not optimized.
Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select New c_Special(cnKan, cnSach, cnLuT)).tolist()

or:

Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select New c_Special With {.Kan = cnKan, .Sach = cnSach, .LuT = cnLuT}).tolist()



You can put the object creation in the select statement, no need to loop through the results and build another list.

Other than that, you're all set.
is your suggestion above the C# way of doing this?

some thing like this
Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select New c_Special With ( .Kan = cn.Kan, .Sach = cn.Sach, .LuT = cn.LuT )).tolist

Open in new window


I am not on my PC to see this working thus the words "something like this"


Anytime you see Select, New, and With, that is the VB.NET way.  Also, you need the braces, and not parentheses.
This syntax became available in .NET 3.0 (vs 2005).

It allows you to create an object and assign the property values without having to create a separate overload of your constructor for each property combination.

It is basically the same as:

dim obj = New obj()
with obj
  .PropertyA = valueA
  .PropertyB = vallueB
end with

but it steamlines the syntax a little further. This was available in C# in earlier versions, but was introduced in VB.NET recently. So you could call it the C# way of doing things, but it is actually a fully supported new feature to VB.NET. They're called object initializers.

A full description can be found here:
http://msdn.microsoft.com/en-us/library/ms364068(v=vs.80).aspx
I got back to my working computer and could try it after all. For a single this works

Dim casenames = (From cn In db.tbl_tests Where cn.Bear = lc _
                         Select  New c_Special ( cn.Kan, cn.Sach, cn.LuT )).single

Open in new window


So I imagine it all works the same for a list.
I guess that it would as long as you have a constructor for the c_Special class, but I haven't done that with VB.NET syntax, so I didn't think that it was supported.  Thank you for the clarification!!
Thanks guys.

To finish off this thread I would like to add something here about whether letting WCF do the serialization or to do it yourself.

The problem is if you return a string in your WCF and do the serialization with the datacontractjsonserializer then you will get "QUOTES" wrapped around your result.

Depending on the consumer this is not good.

Thus at the end of the day the way I have dealt with this in keeping with my above is that I am returning my class above or List(of myclass) then letting WCF do the serialization.  Also I made WCF wrap the result so that the JSON has an outer name.

My consumer is an iphone app.

Thus my end result looks like this

{"counselResult":[{"cwID":1,"cwshortname":"DON","cwlastname":"Duck","cwfirstname":"Donald"},{"cwID":2,"cwshortname":"SPA","cwlastname":"Sparrow","cwfirstname":"Jack"}]}

Open in new window


Where the name "counselresult" is just how WCF wraps it.

Thank you guys.

As I am sure I am only about a day or 2 from my next question I hope I share points here in an approving manner.
Thank you again.