I'm having a problem using WCF and Entity Framework 4.1 POCO objects (generated using T4 templates). My basic problem is that when sending a POCO object from my client to the service, WCF is deserializing a member variable of type ICollection as a fixed size array.
On the client side I can tell visual studio to use IList instead of T[] - but I cant see any option like this on the server end.
This causes no end of problems with several things, such as persisting these objects back to the database.
Is there any way to tell WCF what object type to deserialize ICollection (or any array) as?
I'm surprised that more folks haven't run into this issue, as it hits you smack in the face when you try to use the EF T4-generated POCO objects over WCF. Specifically, the error I was getting said something like:
Exception: "Unable to set field/property Orders on entity type Datalayer.Customers. See InnerException for details."
InnerException: "An item cannot be added to a fixed size Array of type 'Datalayer.Order[]'."
At any rate, the only solution I've been able to come up with is the one that you mention, namely, modifying the T4 templates to use HashSet instead of ICollection. Doesn't strike me as the cleanest, but it seems to work.
I'm using Entity Framework 6, and I was able to solve this issue by making the following changes in my T4 template.
I changed the following line where it creates the navigation properties to use a List instead of a collection from
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,
to
navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("List<" + endType + ">") : endType,
Then I changed the code that sets the navigation property in the constructor to convert the default hashset to a list by adding a call to .ToList(). This line
this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();
was changed to
this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>().ToList();
The HashSet<>.ToList() method is an extension, so in order to make that extension method available, I added a using System.Linq statement by modifying the UsingDirectives method:
public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
? string.Format(
CultureInfo.InvariantCulture,
"{0}using System;{1}" + Environment.NewLine +
"{0}using System.Linq;" +
"{2}",
inHeader ? Environment.NewLine : "",
includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
inHeader ? "" : Environment.NewLine,
Environment.NewLine)
: "";
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With