I've been reading about serialization of entities graph in an entity framework context using Linq to entities and the different possible serializers: Binary, XmlSerializer and DataContractSerializer.
As i understood the binary and XmlSerializer serialize the entity without its relationships. In case relationships are serialized it would cause a problem because of the nature of the resulting xml file structure ( for XmlSerializer).
The DataContractSerializer serialize the graph in its whole depth unless the lazy load is disabled.
My question is: I want to serialize a part of the graph. For example if I have an entity A and three related entities B, C and D, only B and D would be serialized with A. I want to use the the DataContractSerializer. If I delete the [DataMemberAttribute] of the unwanted navigational properties would that work?
You can actually disable lazy-loading, serialize/deserialize, and then re-enable lazy-loading.
context.ContextOptions.LazyLoadingEnabled = false;
StackOverflow Source
Since attributes are static metadata you can't mess with them at run-time. And if you remove them from your entity they will be permanently removed.
The Lazy loading isn't probably what you want, since when you load you bring the entire graph, the partial graph cenario only usually comes up on updates or partial inserts.
Your cenario, from what I gathered is when you want to update something, you want to update a partial graph only, and not the entire graph that you have on the client. One way to achieve this is to remove manualy the other DataMembers and set them to null, serialize them, update, and them repair the null references you previously set, finally make sure the ChangeTrackers are all in their previous state.
In our specific development cenario, we achieved this behaviour through a T4 template, that generates all the messy code, generating part of a "DataManager" that handles all the Self Tracking Entities once they exist on the client.
In my experience, it seemed like the only reliable way to disable lazy-loading is to go to the Entity Designer winder, right-click in the background, select "Properties", and set "Lazy Loading Enabled" to false in the Properties window.
Related
When i don't have anything in my 'bookings' table my GET endpoints for my customer and Accommodation table work perfectly. Once i create a booking every get request for each table returns every entry in every table.
This is my data model
This is my get request for customers
// GET: api/Customer
[ResponseType(typeof(Customer))]
public async Task<IHttpActionResult> GetCUSTOMERs()
{
var customers = await db.Customers.ToListAsync();
return Ok(customers);
}
When i call a get request for the customer table i only want customer data how can i do this?
An entity framework model has lazy loading enabled by default.
When you return Ok(customers); the API will attempt to serialize the entities so that they can be sent as (probably) JSON or XML. As it serializes through each customer entity it will encounter the Bookings property. As the serializer is requesting that property, Entity Framework will "lazy load" in the bookings which are associated with the customer. Then the serializer will attempt to serialize each booking and hit the Accommodations property... and so on.
Your code above is returning all customers, so you will end up returning every accommodation which has been booked. I expect if you made a new Accommodation which had no bookings, it would not be returned in the output from this call.
There are several ways you can prevent all this from happening:
Disable Lazy Loading
You can disable lazy loading on an EF model by opening the model, right click on the white background of the model diagram and choose "Properties", then set "Lazy Loading Enabled" to "False".
If you have other functions where you want to access the related properties from an entity, then you can either load them in to the context with an "Include" or load them separately and let the EF fixup join the entities together.
My personal opinion is that disabling lazy-loading is generally a good idea because it makes you think about the queries you are making to the database and you have to be much more explicit about asking for what data should be returned. However, it can be a lot more effort and is probably something to look at when you start trying to optimise your application rather than just getting it working.
This Microsoft page "Loading Related Entities" also explains various options (as well as describing exactly the issue with lazy loading your entire database!).
Map Your Entities and Return DTOs
You have more control about how the code traverses your model if you map the entities from EF into DTO's.
From an API perspective using DTOs is a great idea because it allows you to more or less define the output of an endpoint like an interface. This can often remain the same while the underlying data structure may change. Returning the output of an EF model means that if the model changes, things which use that data may also need to change.
Something like AutoMapper is often used to map an EF entity into DTOs.
Serializer Settings
There may be some media-type formatter settings which allow you to limit the depth of entities which will be traversed for serialisation. See JSON and XML Serialization in ASP.NET Web API for a place to start.
This is probably too broad of a change, and when you want to actually return related objects would cause a problem there instead.
I've got a couple of entities in a parent-child relationship: Family (parent) and Updates (child). I want to read a list of families without the corresponding updates. There are only 17 families but about 60,000 updates so I really don't want the updates.
I used EntitiesToDTOs to generate a DTO from the Family entity and to create an assembler for converting the Family entity to the FamilyDTO. The ToDTO method of the assembler looks like:
public static FamilyDTO ToDTO(this Family entity)
{
if (entity == null) return null;
var dto = new FamilyDTO();
dto.FamilyCode = entity.FamilyCode;
dto.FamilyName = entity.FamilyName;
dto.CreateDatetime = entity.CreateDatetime;
dto.Updates_ID = entity.Updates.Select(p => p.ID).ToList();
entity.OnDTO(dto);
return dto;
}
When I run the assembler I find each resulting FamilyDTO has the Updates_ID list populated, although lazy loading is set to true for the EF model (edmx file). Is it possible to configure EntitiesToDTOs to support lazy loading of child elements or will it always use eager loading? I can't see any option in EntitiesToDTOs that could be set to support lazy loading when generating the assembler.
By the way, I'm part of a larger team that uses EntitiesToDTOs to regenerate the assemblers on an almost daily basis, so I'd prefer not to modify the assembler by hand if possible.
I'm Fabian, creator of EntitiesToDTOs.
First of all, thanks a lot for using it.
What you have detected is in fact what I don't want the Assembler to do, I want the developer to map the navigation properties only if needed using the partial methods OnDTO and OnEntity. Otherwise you run into problems like you have.
Seems like I never run into that problem using the tool, THANKS A LOT.
So right now I'm fixing this. It's now fixed in version 3.1.
Based on the code that you've posted here, and based on how I think someone would implement such a solution (i.e. to convert records to a DTO format) I think that you would have no choice but to do eager loading.
Some key points:
1) Your Updates_ID field is clearly a List, which means that it's hydrating the collection right away (ToList always executes. Only a regular IEnumerable employs deferred execution).
2) If you're sticking any sort of navigation property in a DTO it would automatically be loaded eagerly. That's because once you so much as touch a navigation property that was brought back by Entity Framework, the framework automatically loads it from the database, and doesn't care that all you wanted was to populate a DTO with it.
I am using EF4, and I using the System.Data.Entity dll in my class. However, I can't see the load method of my navigation property of my entity.
How can I access to this method?
What I am doing is create e 4.0 project of .NET, create my edmx from a database, right click in the model edmx and I generate a DBContext.
However, I can access to the local property of my context, that I think that is a feature of EF4.
Thanks.
Daimroc.
For the DbContext approach, the IsLoaded property and Load method have been moved:
context.Entry(yourEntity)
.Collection(entity => entity.NavigationProperty)
.IsLoaded;
context.Entry(yourEntity)
.Collection(entity => entity.NavigationProperty)
.Load();
Entry method: http://msdn.microsoft.com/en-us/library/gg696578(v=vs.103).aspx
Collection method: http://msdn.microsoft.com/en-us/library/gg671324(v=vs.103).aspx
IsLoaded property: http://msdn.microsoft.com/en-us/library/gg696146(v=vs.103).aspx
Load method: http://msdn.microsoft.com/en-us/library/gg696220(v=vs.103).aspx
When you write the query (all this also works with lambda syntax as well btw)
From a in context.EntitySet.Include("Navigation Property NAme")
select a
and all will be there ;) .. or more to the point the navigation properties will be populated.
can be wierd with lots of joins though
you can also
From a in context.EntitySet.Include("Navigation1.Navigation2.Navigation2")
.Include("SomeOtherNavigation")
select a
where navigation1 and SomeOtherNavigation are navigation properties on the entity set
Failing that you can turn on lazy loading in the context. But its evil imo.
Also it doesnt really scale well when you go for an SOA approach as you need to include prior to knowing about the lazy load in your repository.
Ie you run the query in your repository, send stuff over the service and then want the navigation properties in the front end ... by which time its too late to lazy load ... EG you are using a wcf service that doesn't use data services.
Important to note that you ahve to use Include on the EntitySet, it is not on an IQueryable<>.
A real example:
var csg = from ucsg in c.UserCarShareGroups.Include("UserCarShareGroups.User.UserVehicles")
where ucsg.User.UserName.ToLower() == userName.ToLower()
&& ucsg.CarShareGroup.Carpark.Name.ToLower().Equals(carparkName.ToLower())
&& ucsg.DeletedBy == null
select ucsg.CarShareGroup;
(the database has case sensitive collation for some reason)
An alternate approach (and maybe more relevant is here)
Entity Framework - Trouble with .Load()
However I like doing it the way I said because it is explicit and I know exactly what is being pulled out. Especially when dealing with large datasets.
An answer to a question that combines my concerns with Load() is here:
Entity Framework 4 load and include combine
I'm trying to return lists of objects that have references to another objects and viceversa.
I only want the lazy load to get the "first level children", I mean, if I have a "Person" object with a "Place" property, I want the place data to be loaded but not every object in "Place" object needs to be loaded... because this would ahead to a cyclic reference...
I've read that I could do this by using [DataContract(IsReference = true)] on every Object.
I've set every object in the model (auto-generated by EF) with that decoration but it's still failing when trying to send it back to the service caller.
Am I missing anything? Thanks in advance.
I have used the [DataContract(IsReference=true)] successfully to solve the cyclic dependency issue in the past. Admittedly they were not objects generated by EF, but I' not sure how much that should matter.
What is the exact error?
Is it that the graph is getting to big?
Could it be that your objects are not the same instances, but different instances of the conceptually same type?
So when your TypeA-instance1 gets serialized and it has a reference to TypeB-instance1 which has a Reference to TypeA-instance1 the 2 actual TypeA-instance1 objects to not compare equal so the serializer does not attempt to reuse the references?
You could override the equals method on your objects and do some equality testing based on properties of your object rather than the default memory address that will be used.
I mean, if I have a "Person" object
with a "Place" property, I want the
place data to be loaded but not every
object in "Place" object needs to be
loaded...
That is not possible when using lazy loading. Once the entity gets serialized the serializer will access every single property. Accessing every navigation property will trigger lazy loading and serializer will continue with loaded properties => it will always serialize complete object graph. In your scenario it can mean:
Serializer will start with a Person which have navigation property to Place
Lazy loading will load the Place and serializer will serialize.
If the Place have navigation property to all Persons lazy loading will trigger and load all persons referencing the Place!
Serializer will start serializing every single loaded Person - if IsReference is set to false you will get exception with cycles in object graph. If not it will create huge message.
That is very basic explanation what happens if you try to serialize object when using lazy loading. If your entities have other navigation properties the same effect will happen for them. In the worst case you can easily build an operation which will try to pull and serialize all data from the database. That will most probably lead to timeout.
There is one more problem with lazy loading. Serialization takes place outside of operation scope. So if you close / dispose ObjectContext in the operation you will get an exception when entity triggers lazy loading.
Don't use lazy loading when exposing entities on WCF or use DTO to control what data should be passed from the operation.
You may want to convert your object tree to other, flat objects and return those instead.
I have a set of linq to sql classes and serialized them into JSON using the .NET JavaScriptSerializer.
However, as soon as I add record onto a relating table, serialization throws a "Circular reference exception". Aaarggh!
It's described in detail here.
I have a few options
Convert the linq to sql class to a class with no relationships thus avoiding the circular reference
snip the circular reference by nulling associations - i don't consider this to be a real option
Use ScriptIgnoreAttribute (somehow). I couldn't easily apply this because the properties are in generated classes and LINQ to SQL doesn't automatically honor buddy classes
Use JSON.NET and somehow use attributes + buddy classes to stop the serializer trying to walk across relationships.
Has anyone else encountered this? I would really prefer the last option if possible but I don't know how to do this.
Any help is greatly appreciated
The latest version of Json.NET supports serializing circular relationships. Check out Preserving Object References in the help.
Additional link for accepted answer
Json.NET Help, Preserving Object References (with example)
It seems it works fine with LINQ to SQL
James's solution solved part of my problem. I needed to exclude certain List Types within the object. To solve my problem, I just copied the parts of the object I needed. The following is an example.
var DB = new DBDataContext();
var lUsers = new List<User>();
DB.Users.ToList().ForEach(x => lUsers.Add(new User()
{
ID = x.ID,
FIRST_NAME = x.FIRST_NAME
}) );