Disabled lazy downloads and links to download objects do not work properly

I worked with WCF RIA and Silverlight services and had some success in exposing a service that serves data retrieved from an ADO.NET entity data model modeled from an existing SQL Server 2008 Express database. The database defines many relationships between tables, which I hope to use the client side to bind data.

Everything went smoothly until I tried the following service method:

public IQueryable<Timeline> GetHighlights() { var self = from x in Database.Timelines where User.Id == x.UserId || User.Id == x.SenderId select x; var friends = from x in Database.FriendItems where User.Id == x.UserId from y in Database.Timelines where x.FriendId == y.UserId || x.FriendId == y.SenderId select y; return self.Concat(friends).OrderByDescending(s => s.Id); } 

Note. A "user" is an internal property of a class that selects an authenticated user, and Database simply transfers the ObjectContext property (for convenience).

The Timeline entity contains 2 User and Sender navigation properties that are associated with the SilverfishUser entity. When I repeat the results from the query "I", I see that the previously mentioned properties were filled in by the current user (which is true). However, when I repeat the results of the query "friends", both properties have a value of zero (before being serialized to the client).

I tried setting:

 this.ContextOptions.LazyLoadingEnabled = false; //and this.ContextOptions.ProxyCreationEnabled = false; 

And I also tried to load links using the Include request method (with lazy loading with enabled and disabled) to no avail.

The only way I successfully populated the User and Sender properties of a Timeline object was using the following statement:

 friends.ForEach(s => { if (!s.UserReference.IsLoaded) s.UserReference.Load(); if (!s.SenderReference.IsLoaded) s.SenderReference.Load(); }); 

From what I understand, the β€œDownload” operation leads to a separate query running in the database. As you can see, this presents a potentially inefficient situation where the user has many friends with many timeline messages. The exact situation I'm trying to avoid by disabling lazy loading. I want to return to the client a fully loaded object that can be associated with as few requests as possible.

I have already overcome one problem when relative properties were not serialized for the client by using the [Include] attribute in the metadata property definitions created by the domain service wizard. This question seems a bit more complicated, the solutions I tried were widely stated by others and should solve my problem theoretically, but they do not. Again, the only way I was able to successfully populate the object is to explicitly load links using the generated EntityReference <> property created for the property associated with it.

Any help, experience or information on this issue is welcome.

[EDIT] Updating some of my research when I execute this query:

  var friends = Database.FriendItems .Include("Friend.Timeline") .Where(s => User.Id == s.UserId); 

And to access the navigation properties ("friends.First (). Friend.Timeline.First (). User"), the value is not zero. This is only when I select a time frame in a new collection, adding something like:

 .SelectMany(s => s.Friend.Timeline); 

That navigation properties no longer matter. Now this is just an assumption, but I can only assume that it implements the property values ​​in an instance of a new object, so it does not re-populate these properties in an attempt to avoid circular references? In any case, this is one feature of the brine to solve. Hopefully there is someone who knows more about this than I do.

+4
source share
1 answer

Well, I managed to find a little workaround, although not very elegant. I will send it as an answer so that people can look at it, but I am going to leave the question open and bring a more suitable solution, if possible.

Here is my fix:

 public IQueryable<Timeline> GetHighlights() { var self = from x in Database.Timelines where User.Id == x.UserId || User.Id == x.SenderId select x; var friends = from x in Database.FriendItems.Include("Friend.Timeline") where (User.Id == x.UserId) select x.Friend.Timeline; List<Timeline> highlights = new List<Timeline>(); highlights.AddRange(self); friends.ForEach(x => x.ForEach(y => highlights.Add(y))); return highlights.AsQueryable().OrderByDescending(s => s.Id); } 

I think this works by creating a new collection manually, I hinder the design of objects into new objects, while preserving the loaded relational properties. Again, this is just speculation, but speculation follows a pretty good pattern.

0
source

All Articles