New Posts New Posts RSS Feed: Async Projections, Navigation Properties and Fake Entity Managers
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Async Projections, Navigation Properties and Fake Entity Managers

 Post Reply Post Reply
Author
JoeGershgorin View Drop Down
Newbie
Newbie


Joined: 24-Feb-2010
Location: USA
Posts: 14
Post Options Post Options   Quote JoeGershgorin Quote  Post ReplyReply Direct Link To This Post Topic: Async Projections, Navigation Properties and Fake Entity Managers
    Posted: 13-May-2011 at 6:41pm
Running DevForce 6.0.9 under Silverlight 4.

I have a POCO that is roughly structured like this (it's in my Silverlight domain model project and linked in the BOS domain model project):

[DataContract]
public class PasSummary : IHasEntityAspect, IKnownType
{    
    [Key]
    public Guid Id { get; set; }
    
    [DataMember]
    public PasNumber PasNumber { get; set; }

    [DataMember]
    public int Number { get; set; }

    [DataMember]
    public string Description { get; set; }

    [DataMember]
    public string Function { get; set; }

    [DataMember]
    public Decimal TotalHours { get; set; }               
  
    [DataMember]
    public IEnumerable<Project> Projects { get; set; }

    [IgnoreDataMember]
    public EntityAspect EntityAspect { get; set; }        
}

I have an Async projection that roughly looks like this:
 var getEntriesForWeekOp = Manager.TimeSheetEntries
        .Where(p =>
        p.TimeSheet.UserId == _currentUser.Id &&
        p.TimeSheet.WeekEndingDate == date.Date)                    
        .Include("TimeSheet")
        .Include("Project.PasNumber.PasFunction")
        .GroupBy(timeSheetEntry => timeSheetEntry.Project.PasNumber)
        .Include("Projects.PasNumber.PasFunction")
        .Select(timeSheetEntries=>                        
            new PasSummary{                        
            TestObject = timeSheetEntries.ToList(),                        
            PasNumber = timeSheetEntries.FirstOrDefault().Project.PasNumber,
            Number =  timeSheetEntries.FirstOrDefault().Project.PasNumber.Number,
            Description = timeSheetEntries.FirstOrDefault().Project.PasNumber.Description,
            Function = timeSheetEntries.FirstOrDefault().Project.PasNumber.PasFunction.Name,
            Projects = timeSheetEntries.Select(entry=>entry.Project).Distinct().ToList(),            
            TotalHours = timeSheetEntries.Where(ts=>ts.ActualHoursForWeek.HasValue)
                                         .Select(tse=>tse.ActualHoursForWeek.Value).Sum()
        })                    
        .ExecuteAsync();

Problem 1: (Navigation Properties)
The PasNumber is a entity type. It has a navigation property called PasFunction. If I project PasNumber into PasSummary's PasNumber property all the navigation properties are null. Ommiting or adding the includes has no effect. However if I project the navigation property values (Such as in the above Function property) the values feeds in fine. When using a fake entity manger backing store the PasFunction navigation property is retained.

Problem 2 : Projecting collections differences when using a fake entity manager backing store:

The assignment of the "Projects" property in PasSummary in the above projection throws with the following exception when using a real entity manager:
LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[ProjectVisionModel.Project] ToList[Project](System.Collections.Generic.IEnumerable`1[ProjectVisionModel.Project])' method, and this method cannot be translated into a store expression.

If I ommit the .ToList() the assignment works fine, but then when using the fake entity backing store causes the following exception:
Type 'System.Linq.Enumerable+<DistinctIterator>d__81`1[ProjectVisionModel.Project]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute.  If the type is a collection, consider marking it with the CollectionDataContractAttribute.  See the Microsoft .NET Framework documentation for other supported types.

So it seems the fake backing store hates ommiting the .ToList() and the real entity manager hates it when the .ToList() is there.

Any feedback you could provide on the recommended way to deal with these issues would be appreciated, thanks.


Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 667
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 17-May-2011 at 11:45am
Hi Joe;

I'm going to repro this on my machine and get back to you as soon as possible. Sorry for the delay.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 667
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 17-May-2011 at 5:11pm
Hi Joe;

Problem 1 seems to be a bug. I will file a bug report for this. For now, the workaround is to project a completely anonymous type and then create the new PasSummary POCO object from it. You also don't need to use .Include when doing projection. This is because projection query are done on the server so navigational properties can be fetched immediately.

Problem 2:

- The first LINQ to Entities exception is an EF limitation. In general, whenever you see this exception, it means that it's an EF limitation. This ToList() call works against the fake backing store because we're not working against EF in this environment.

- The second DistinctIterator exception is a bug. I will also file a bug report for this.

For now, the workaround for problem 2 is to switch between using .Distinct().ToList() and just .Distinct() between the fake and the non fake backing store. After the bug is fixed, the right way to do this is to just use .Distinct().

I hope this is clear. Please let me know if you need further clarification.
Back to Top
JoeGershgorin View Drop Down
Newbie
Newbie


Joined: 24-Feb-2010
Location: USA
Posts: 14
Post Options Post Options   Quote JoeGershgorin Quote  Post ReplyReply Direct Link To This Post Posted: 18-May-2011 at 12:53pm
Thanks Denis, I'll probably get an opportunity to get back to this issue tomorrow and will let you know. I've already implemented if/else workaround to use/notuse ToList() depending on the entity backing store, it will be nice to have a single code base for both backing stores when the bug is fixed, thanks.
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 104
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 19-Jun-2011 at 12:08pm

Is this fixed in 6.1.0 or 6.1.1? I don't see anything in the release notes to indicate it was.  The reason I ask is that in 6.0.9, using the Distinct on a simple projection fails.  This is running on the Silverlight Client against cache only if that makes any difference. 

//Try this in NorthwindIB (assuming you've already loaded the orders into the EM.
// both properties are ints and is the same thing I'm doing in our data model
var testing = _entityManager.Orders.With(QueryStrategy.CacheOnly)
.Select(x => new {x.OrderID, x.EmployeeID}).Distinct();
 
// will throw the exception on the first iteration
foreach (var v in testing)
{
   if (v.EmployeeID >= 0)
    {}
}
 
Exception Type: System.InvalidCastException
Message: Unable to cast object of type '<>f__AnonymousType14`2[System.Int32,System.Int32]' to type '_IB_f__AnonymousType14`2g2sDsTuu_pDiPtoeb[System.Int32,System.Int32]'.
Data: System.Collections.ListDictionaryInternal
StackTrace Information
*********************************************
   at lambda_method(Closure , Object )
   at IdeaBlade.Core.AnonymousFns.<DeconstructMany>d__e.MoveNext()
   at IdeaBlade.Core.AnonymousFns.<ConstructMany>d__0.MoveNext()
   at System.Linq.Enumerable.<CastIterator>d__b1`1.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at IdeaBlade.EntityModel.EntityQuery`1.ExecuteExpression()
   at IdeaBlade.EntityModel.EntityQuery`1.ExecuteCacheQuery()
   at IdeaBlade.EntityModel.EntityQueryFinder.ExecuteFind(Guid queryGuid)
   at IdeaBlade.EntityModel.EntityQueryFinder.Execute()
   at IdeaBlade.EntityModel.EntityManager.ExecuteQueryCore(IEntityQuery query, Boolean isAsync)
   at IdeaBlade.EntityModel.EntityManager.ExecuteQuery[T](IEntityQuery`1 query)
   at IdeaBlade.EntityModel.EntityQueryExtensions.Execute[T](IEntityQuery`1 query)
   at IdeaBlade.EntityModel.EntityQuery`1.GetEnumerator()

If instead I use GroupBy, it works fine except of course, the entire entity ends up being retrieved (it's not a projection anymore):

var testing = _entityManager.Orders.With(QueryStrategy.CacheOnly).GroupBy(x => new {x.OrderID, x.EmployeeID}).Execute().ToList();

// will throw the exception on the first iteration
foreach (var v in testing)
{
   // will need to treat as key/value pair now
   if (v.Key.EmployeeID >= 0)
    {}
}
 
 
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 104
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 20-Jun-2011 at 10:01pm
Just upgraded to 6.1.1 and this still isn't fixed.  The Distinct iterator doesn't work even with a simple projection. 
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 667
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 21-Jun-2011 at 6:58pm
Hi pk55;

The previous posts were talking about using Distinct with a POCO object on a projection. Your issue, although may sound similar, is actually different. 

I've filed a bug report for this as well. This query apparently only fails in SL CacheOnly query. It works on 2-tier, n-tier and SL DataSource query. I'm assuming you want a patch for this as well once it becomes available?
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 104
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 21-Jun-2011 at 7:11pm
Yes a patch would be great, thanks for looking into this.
Back to Top
pk55 View Drop Down
Senior Member
Senior Member


Joined: 22-Jul-2009
Location: CA
Posts: 104
Post Options Post Options   Quote pk55 Quote  Post ReplyReply Direct Link To This Post Posted: 22-Jun-2011 at 5:33pm
One last clarification; it seems that any SL CacheOnly query that uses a projection fails when trying to iterate over it or just sending it to a list.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 667
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 23-Jun-2011 at 2:15pm
pk55;

Yes you're right. I've submitted these 2 bugs with a high priority. I'll send you a patch as soon as they're available.
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down