Circular reference exception when serializing LINQ to SQL classes - c#

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
}) );

Related

Using .Include() in a database query creates an infinite loop of data

The problem: I'm using a LINQ to query against an Entity Framework context to a relational database. Following along with EFCore Relationships, I made a database with a few relationships, but when I sent the data to the server using ASP.NET, I got null values for these relationships.
With a little more digging, I found that I needed to use _context.Post.Include("Blog") to send the data since it uses lazy loading. However, by doing this, it created an "infinite loop" in the JsonResult.
The data that ends up getting returned appears to be cut in half and I get JSON parse errors when loading it because it's missing the second half of the JSON data.
Example return value
{"id": 0, "blogId": 1, "blog": {"postId":0
That's all it returns, as anything after that postId would be a reference back to the original post, which in turn has a reference to the blog. Is there any way that I can use LINQ to exclude the post object in the return, similar to how the blog was included in the first place?
This is JSON serialization problem.
Search how to solve "circulare references" problem in your JSON stream serializer documentation.
Different stream serializers provide different solutions:
configure max depth
history based on references cache
configure specific types serializers to do not use "navigation properties"
Other solution - do not use stream serializers - configure serializer function at place.
And another one - use DTO classes (where there are no circular references).
You can also try to detach your entities and set null to every navigation property you want to ignore but this is ugly and can't be recommended.
Fixed! I took the model that came from the database with the relationship included, then used a foreach to null out the reverse reference.
var blog = await _context.Blog
.Include(x => x.Posts)
.SingleAsync(x => x.Id == id);
foreach (Post post in blog.Posts)
{
post.Blog = null;
}
return Ok(blog);

Mapping List<dynamic> using Slapper

I've got the following code snippet in a repository class, using Dapper to query and Slapper.Automapper to map:
class MyPocoClass{
MyPocoClassId int;
...
}
//later:
var results = connection.Query<dynamic>("select MyPocoClassID, ...");
return AutoMapper.MapDynamic<MyPocoClass>(results).ToList();
results above has many items, but the list returned by AutoMapper.MapDynamic has only one item (which is clearly wrong). However, I found that adding the following configuration to AutoMapper fixes the problem:
AutoMapper.Configuration.AddIdentifier(typeof(MyPocoClass), "MyPocoID");
Why does Slapper.AutoMapper need to know the key of my class to simply map a list to another list? Is it trying to eliminate duplicates? I'll also note that this only happens while mapping a certain one of my POCOs (so far)...and I can't figure out why this particular POCO is special.
Turns out this is a bug in Slapper.AutoMapper.
The library supports case-insensitive mapping and convention-based keys. The SQL result set has MyPocoClassID and the class itself has MyPocoClassId -- which is not a problem for Slapper.AutoMapper as far as mapping goes. But internally Slapper.AutoMapper identifies (by convention) that MyPocoClass has MyPocoClassId as its identifier, and it can't find that field in the result set. The library uses that key to eliminate duplicates in the output list (for some reason), and since they're all 'null/empty', we get only one record.
I may submit a pull request to fix this problem, but since the library appears to be unmaintained I don't think it'll help.

Entity framework and DataContractSerializer

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.

Entity framework autogenerated table names

Using Entity Framework one often writes queries such as
var orders = from o in context.Orders.Include("Customer")
where o.OrderDate.HasValue && o.OrderDate.Value.Year == 1997
orderby o.Freight
select o;
What really makes my stomach churn is the "Customer" string argument. I have a hard time believing that EF does not generate table names as constants somewhere. Does anyone know a better approach than to using a string? for the Include fetch option?
EF 4.1 has strongly typed version of Include usable for IQueryable, ObjectQuery and DbQuery. Once you add reference to EntityFramework.dll (EF 4.1) you can add using System.Data.Entity and use eager loading with lambda expressions
// get Orders with related Customers
var orders = from o in context.Orders.Include(o => o.Customer) ...
Edit:
If you don't want to use EF 4.1 check this article. I already used in my project and I'm happy with it.
IMO GetType might help you other than .edmx file where all the definitions is stored,
context.Orders.Include(CustomerEntity.GetType.Name or full name )
How about
Include(context.Customers.EntitySet.Name)
?
You can create a Text Template which will allow you to generate the code in addition to EF's default code. You can do this by right click and clicking "Add Code Generation Item".
In this text template, you can create your constants as you need in "CustomerProperties" and create constant name for each navigation property.
http://msdn.microsoft.com/en-us/data/gg558520

Caching POCO objects in Entity Framework 4.0

I have a database with a bunch of reference tables like States, Languages, etc.. I would like to be able to cache these tables and then use those types in any ObjectContext I want. So in pseudo code I want to be able to do something like this
var db1 = new PatientObjectContext();
Cache.CacheStates(db1.States.ToList())
var person = new Person { State = Cache.GetState("PA")} ;
var db2 = new PatientObjectContext();
db2.People.Add(person)
db2.SaveChanges();
I saw this blog post (http://blogs.msdn.com/b/alexj/archive/2009/04/22/tip-14-caching-entity-framework-reference-data.aspx). But this didn't apply to me because I think it is not using POCO's. When I try to attach the cached object to the objectContext, I get an exception because an object with that primary key is already in that contexts states collection.
It seems that caching reference tables should be a pretty common problem, but I cant seem to find any straight forward solutions for this.
Alex's post is every bit as relevant to POCO entities as to non-POCOs. Why do you think it isn't?
I figured out what I was doing wrong. Before attaching the cloned cached object to the new context I needed to make sure that it is not already attached. Because attaching the same object 2 times was throwing an exception. So I found some code that lets me check if an Item is already in the context before attaching it.
Is is possible to check if an object is already attached to a data context in Entity Framework?

Categories

Resources