I have searched in google for 3 days without any success.
I am using the Database First approach then generated the classes. What I need to do now is to Serialize my entity into Json and then either save to a file or send to another party using Web API (certainly they will be deserialized and consumed later)
The problem here is that EF6 trying to includes all the Navigation Properties, and makes the serialization / deserialization extremely difficults. Setting the properties below doesn't work at all.
Configuration.LazyLoadingEnabled = false;
Configuration.ProxyCreationEnabled = false;
Is there an easy way telling EF6 to just ignore those Navigation Properties all together when serializing? Since I am using the DB first approaches, I have access to all related tables with their foreign keys.
Thanks in Advance.
Try using Newtonsoft.Json; nuget for the serialization.
To serialize:
string json = JsonConvert.SerializeObject(MyObjects, Formatting.Indented);
Inside your class MyObject, you just add a [JsonIgnore] annotation above properties you want to skip (Navigation props among others)
Related
I'm querying my database using EF DB first and i have my "news" area that is linked to several other areas and i don't want to load the relationships of this object. What options do i have to do it ? I'm working with WebApi 2 and returning the data as JSON to my application.
I know some options that i have tried:
Create a second class with the fields i want and map it using the LINQ select;
Remove them manually setting them as null.
I don't really like those options because the second one doesn't sounds right and the first one feels like redoing work and i was wondering if there's a better option to solve this.
Your options here are probably:
Make DTOs specific for your "news" area, that will contain only information, that you need to return, use some kind of Mapper to map from your Entity to your DTO. I would recommend that method as it gives you enough flexibility to make your API contract and DB Schema not depend on each other heavily.
Disable Lazy-loading either system-wide or for this specific relationship removing virtual keyword and using .Include(x=>x.Navigation) where you explicitely need those properties.
Make sure to turn off Lazy Loading
this.Configuration.LazyLoadingEnabled = false;
and turn off Proxy Creation
this.Configuration.ContextOptions.ProxyCreationEnabled = false;
Then make sure NOT to use an Include in your LINQ query. HTH
I am trying to create a method that accesses my Entity Framework (database first) context using reflection for a REST web service. I have gotten as far as getting the table, and converting it to a list for returns, but I am running into trouble when I try to use Include to get some of the related tables.
I have a couple tables that I am testing with, they are Project and Person. Project has a reference to Person for the person who manages the project and a reference back from Person to Project for all the projects a person manages. In order to get the original return to work I added
Configuration.ProxyCreationEnabled = false;
Configuration.LazyLoadingEnabled = false;
to my context's class so that the referential loop is removed and the JSON serialization works correctly.
The problem I am facing is that I am now trying to explicitly get all the projects, and the person record related to the project, without including the list of the person's projects. But when I try to include people, I get the JSON serialization error because it is pulling back the circular reference. I currently have the following code:
Entities context = new Entities();
// Normally these will be a parameters to the calling method
string tableName = "Projects";
string includeTableName = "Person";
System.Reflection.PropertyInfo propertyInfo = context.GetType().GetProperty(tableName);
Type type = propertyInfo.PropertyType;
dynamic list = propertyInfo.GetValue(context);
var include = typeof(QueryableExtensions).GetMethod("Include", new[] { typeof(IQueryable), typeof(string) });
var toList = typeof(Enumerable).GetMethod("ToList").MakeGenericMethod(type.GenericTypeArguments[0]);
list = include.Invoke(null, new object[] { list, includeTableName });
return toList.Invoke(null, new object[] { list });
The code executes properly but then I make the call I get the following error:
"Message":"An error has occurred.","ExceptionMessage":"Self referencing loop detected with type 'DDBAPI.EntityFramework.Project'. Path '[8].Person.Projects'."
Is there anyway with Include to stop it from loading the circular reference? I saw similar questions that referenced making DTOs to limit what gets pulled into the return but since normally I will not know what table I will be calling against, I will not know which DTO I would need as I am trying to avoid any logic based around the table names being passed in.
Removing the proxy creation doesn't solve the circular reference problem. It has nothing to do with it.
The proxies are simply created to handle the change tracking, but they have the same properties of the original entities.
Your problem is that there is a navigation property from table Person to Project and viceversa. That's the circular reference, and you could only break it if you removed the navigation property in one of the tables, i.e. the Person property in Project entity, or the Projects property in Person entity.
Most probably you don't want to do this. So, what you need to do is to instruct the serializer so that it can handle the circular references. I suppose you're using JSON.NET, which is the current JSON serializer by default. I do also suppose you're using Web API. If that's the case, you can find the JSON.NET serializer settings like this:
JsonSerializerSettings serializerSettings = GlobalConfiguration
.Configuration.Formatters.JsonFormatter.SerializerSettings;
Then you need to choose one of these two options:
ReferenceLoopHandling = ReferenceLoopHandling.Ignore. Docs here.
PreserveReferencesHandling = PreserveReferencesHandling.Objects Docs here.
There is still another solution: instead of removing one of the navigation properties responsible for the circular reference, you can instruct JSON.NET to not serialize it by decorating it with [JsonIgnore] attribute. Docs here.
I have an EF, database first, set of models that have relationships between themselves as dictated by the DB's foreign keys. When I try to return that object graph from Web API I have problems. I have read countless posts on this site to try to fix my original issue of
Self referencing loop detected for property 'Merchant' with type 'MP.Models.Merchant'. Path 'tickets[0].customer.Merchant.Addresses[0]'.
I know that each Address object has a Merchant property that points back to the Merchant and causes the loop.
I have read that RefenceLoopHandling.Ignore is supposed to just ignore the references, after the initial one, and not serialize them and all should work, but what happens when I do that is I get an infinite loop and my worker process grows to the size of my physical memory and I have to kill it.
Using PreserveReferencesHandling = PreserveReferencesHandling.Objects instead of the .Ignore does work to return all the objects and their references, but I have an iOS app that I assume will not be able to convert that JSON because I have read that you need to deserialize with json.net for this to work.
I don't want to hard code any jsonIgnore attributes on the property collections because there are times when I need that collection populated, like when I am returning a list of addresses and I want their Merchant property populated.
Why isn't .Ignore working as all the other posts on the topic
suggest?
If I have to stick with PreserveReferencesHandling.Objects, how would the iOS app be able to use this JSON format?
Do you have a many-to-many relationship in your model?
I found out (the hard way) that RefenceLoopHandling.Ignore will still get into an infinite loop if you have a many-to-many relationship between two entities and both entities have ICollection navigation properties to each other.
How to solve it? I put [JsonIgnore] on one of those navigation properties. A hack, but works.
I have two tables, MenuItem and SearchTerm. I have a foreign key on SearchTerm that is linked to the primary key on MenuItem.
I'm using the database-first approach with entity framework.
The result of the above is that the models generated will contain references to one another. This allows me to get all the data I need in a single statement
//Where() condition omitted for this example.
IList<MenuItem> menuItems = db.MenuItems.Include("SearchTerm").ToList();
This brings back the data I need. The issue I am having is that when trying to return this data through an ajax call, I get an error Self referencing loop detected in my response. I understand this happens because it is trying to serialize the json and is unable to do so.
Is there a way I can fetch the data so that it will only include the first two levels (MenuItem, MenuItem.SearchTerms), or is this something I should be setting on my ajax request?
There are at least 2 options to solve this problem.
Control json serialization and serialize only required amount of levels Proper JSON serialization in MVC 4
Disable lazy loading on dbContext Turn off lazy loading for all entities
I have a Reason object:
public class Reason
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual Company Company {get;set;}
}
I am using entity framework 4 and Company is navigation property to Company.
I also use webservices in order to return data to the client.
I have web method that returns Reasons:
[WebMethod]
public Reason[] GetCallReasons()
{
IReasonRepository rep =
ObjectFactory.GetInstance<IReasonRepository>();
return rep.GetReasonsList().ToArray();
}
Because of the ef4 I get the following exception for executing the web method:
A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Reason_24A0E4BBE02EE6BC2CF30BB56CFCB670C7D9D96D03D40AF4D174B89C9D3C5537'
The problem accurs because ef4 adds property that can't be serialized:
In order to solve this and eliminate the error, I can disable the navigation property by not making it virtual or by remove the navigation property. But I neet it and want to use the lazy loading feature.
I also can write spesific serializer for Reason but I have many many classes the I used in my web-services and write a serializer for all of them is a lot of work.
How can I solve this exception?..
There are multiple solutions for your problem and they really depend on the type of service you are using and on the type of serialization:
The clean approach is using DTO (data transfer objects) as #Mikael already suggested. DTO is special object which transfers exactly what you need and nothing more. You can simply create DTOs to not contain circular references and use AutoMapper to map between entities and DTOs and vice versa. +1 for #Mikael because he was the first to mentioned this.
All other approaches are based on tweeking serialization as #Haz suggested:
WCF and DataContractSerializer: explicitly mark your entities with DataContract[IsReference=true] and all properties with [DataMember] attributes. This will allow you to use circular references. If you are using T4 template to generate entities you must modify it to add these attributes for you.
WCF and DataContractSerializer: implicit serialization. Mark one of related navigation properties with [IgnoreDataMember] attribute so that property is not serialized.
XmlSerializer: mark one fo related navigation properties with [XmlIgnore] attribute
Other serializations: mark one of related navigation properties with [NonSerialized] (+1 for Haz he was the first to mention this) for common serialization or [ScriptIgnore] for some JSON related serialization.
I usually write specific classes for the webservice. While this is some extra work it has the advantage that the webservice gets more robust as small changes in your entities won't go unoticed and silently fail on the side of the consumer/javascript. For example if I change the name of a property.
There are a few things you can do to reduce the work and one is to use AutoMapper which can automatically map between objects.
You haven't supplied the definition for your company class.... But I'm guessing you have a collection of Reason as a property.
Lazy loading in an SOA Enviroment doesn't really work. You can't have unlimited lazy navigation over a serialized class, once you leave the webmethod you have no way to call back into the original datacontext from the webmethod consumer to lookup the properites... so the serializer will try and visit all properties, including lazy properties at the time of serialization.
You need to disable serialization on one part of the circular reference, either on the Reason collection in Company class, or the Company in Reason class.
You can use the "NotSerialized" attribute to disable serialization of a particular field.