views:

149

answers:

1

I have a problem with protobuf-net and the use of generics.

Given:

    [DataContract]
public class CacheData
{
    [DataMember(Order = 1)]
    public List<CacheLoadItem<int>> Foo;

    [DataMember(Order = 2)]
    public List<CacheLoadItem<int>> Bar;

    [DataMember(Order = 3)]
    public List<CacheLoadItem<int>> XXX;

    [DataMember(Order = 4)]
    public List<CacheLoadItem<string>> YYY;

    [DataMember(Order = 5)]
    public List<CacheLoadItem<int>> Other;

    [DataMember(Order = 6)]
    public List<CacheLoadItem<int>> Other2;

    [DataMember(Order = 7)]
    public List<CacheLoadItem<int>> Other3;

    [DataMember(Order = 8)]
    public List<CacheLoadItem<string>> EvenMore;

    [DataMember(Order = 9)]
    public List<CacheLoadItem<string>> AlmostThere;
}

[DataContract]
public class CacheLoadItem<V>
{
    [DataMember(Order = 1)]
    public int ID;

    [DataMember(Order = 2)]
    public string Name;

    [DataMember(Order = 3)]
    public V Value;
}

The CacheLoadItem with a generic int lists get serialised just fine, but the CacheLoadItem with a generic string lists dont.

I think it has to do with what generic list gets serialized first.

The CacheLoadItem with a generic string lists contains the correct number of items, but with default/null values.

Anyone know why this happens?

A: 

Ok, it is definitely Entity Framework related.

the CacheData is pululated with LINQtoEF.

Like:

                        using (var myDatabase = new MyDatabase(entityBuilder.ToString()))
        {
            result.A = (from a in myDatabase.ATable select new CacheLoadItem<int> { ID = a.ID, Name = a.Name, Value = a.Number }).ToList();
            result.B = (from b in myDatabase.BTable select new CacheLoadItem<string> { ID = b.ID, Name = b.Name, Value = b.Code }).ToList();
            result.C = (from c in myDatabase.CTable select new CacheLoadItem<int> { ID = c.ID, Name = c.Name, Value = c.ID }).ToList();
            result.D = (from d in myDatabase.DTable select new CacheLoadItem<int> { ID = d.ID, Name = d.Name, Value = d.Number }).ToList();
            result.E = (from e in myDatabaseETable select new CacheLoadItem<int> { ID = e.ID, Name = e.Name, Value = e.Number }).ToList();
            result.F = (from f in myDatabase.FTable select new CacheLoadItem<string> { ID = f.ID, Name = f.Name, Value = f.Number }).ToList();
            result.G = (from g in myDatabaseGTable select new CacheLoadItem<string> { ID = g.ID, Name = g.Name, Value = g.Code }).ToList();
            result.H = (from h in myDatabaseHTable select new CacheLoadItem<int> { ID = h.ID, Name = h.Name, Value = h.Number }).ToList();
            result.I = (from i in myDatabaseITable select new CacheLoadItem<int> { ID = i.ID, Name = i.Name, Value = i.Number }).ToList();
        }

Does not work, but the following works.

            using (var myDatabase = new MyDatabase(entityBuilder.ToString()))
        {
            result.A = (from a in myDatabase.ATable select a).ToList().Select(b => new CacheLoadItem<int> { ID = a.ID, Name = a.Name, Value = a.Number }).ToList();
            result.B = (from b in myDatabase.BTable select b).ToList().Select(b=>new CacheLoadItem<string> { ID = b.ID, Name = b.Name, Value = b.Code }).ToList();
            result.C = (from c in myDatabase.CTable select c).ToList().Select(c=> new CacheLoadItem<int> { ID = c.ID, Name = c.Name, Value = c.ID }).ToList();
            result.D = (from d in myDatabase.DTable select d).ToList().Select(d=> new CacheLoadItem<int> { ID = d.ID, Name = d.Name, Value = d.Number }).ToList();
            result.E = (from e in myDatabaseETable select e).ToList().Select(e=> new CacheLoadItem<int> { ID = e.ID, Name = e.Name, Value = e.Number }).ToList();
            result.F = (from f in myDatabase.FTable select f).ToList().Select(f => new CacheLoadItem<string> { ID = f.ID, Name = f.Name, Value = f.Number }).ToList();
            result.G = (from g in myDatabaseGTable select g).ToList().Select(g=> new CacheLoadItem<string> { ID = g.ID, Name = g.Name, Value = g.Code }).ToList();
            result.H = (from h in myDatabaseHTable select h).ToList().Select(h=> new CacheLoadItem<int> { ID = h.ID, Name = h.Name, Value = h.Number }).ToList();
            result.I = (from i in myDatabaseITable select i).ToList().Select(i=> new CacheLoadItem<int> { ID = i.ID, Name = i.Name, Value = i.Number }).ToList();
        }

The difference is that I dont do the transformation in LinqToEF but in LINQtoObjects.

So I guess that EF is broken?

Morten Lyhr
result is of type CacheData
Morten Lyhr
In the first sample with pure LinqToEF. The data is there before the serialization with ProtoBuf, but not after.In the second with LintToObjects the data is there before and after serialization with ProtoBuf.
Morten Lyhr
Well, I'll happily take a look, but an interesting thought : I've seen LINQ-to-SQL drop lazy data during serialization - it only knows about serialization due to the callback API. I can probably come up with a way (especially in "v2") to simply skip the callback API? But if you have found a workaround it might not be worth it?
Marc Gravell