I have situation where Json.Encode is working locally (localhost) which is 64bit iis7 windows 7 box.
If I deploy to windows 2003 32 bit IIS6 I get circular reference errors. Shown below 'Error here' is the line where the error starts.
#*var model = '#Html.Raw(Json.Encode(Model))';*# <<<<Error here
var model = '#Html.GetJson(Model)';
As part of trying to resolve this I thought maybe one of the project dll's that were being used on the server was different than that locally so i copied any reference dll to the server bin directory. This did not help.
I do have a fix which is pretty easy. I would have preferred to be able to identity the issue. My guess is that it is using some dll on the server differently than locally to return json via Json.Encode then on the server.
My resolution as shown 2nd line above is to use Json.Net and a mvc helper
public static MvcHtmlString GetJson(this HtmlHelper htmlHelper, ViewModel vm)
{
string s = JsonConvert.SerializeObject(vm);
return new MvcHtmlString(s);
}
Has anyone seen this and resolved? (without json.net)
Assuming you're using Entity Framework, taking a look at the entities developed by the framework will shed some light on the topic. For example, I had table called Sessions and one called Enrollments, the Enrollments table having an FK relationship to the Sessions table PK. This resulted in the Session objects having a collection of Enrollments, and the Enrollment objects having a virtual instance of the Session that the enrollment was for ... which in turn pointed to a collection of Enrollments etc ... you get the picture, AND why the circular reference issue was detected by the json serialization.
The solution was to NOT query a collection of Session objects in the code, but to query an anonymous (untyped) object with all the same fields in it instead. The prevents the Json.Encode() from getting confused about, since it doesn't know about, the circular reference that Entity Framework is OK with in the code behind / server side code.
Related
I have recently changed from ObjectContext to DbContext using EntityFramwework by upgrading to EF6
Most stuff works, but saving and updating won't. Here is an example:
public void AssignToAdmin(Product product, Admin admin)
{
var pcsps = from s in context.ProductCreationSections
join pcsp in context.ProductCreationSectionAndProducts on s.ProductCreationSecitionID equals pcsp.ProductCreationSectionID
where pcsp.ProductID == product.ProductID && s.IsManagerAssigned
select pcsp;
foreach (var pcsp in pcsps.Include("AssignedAdmins"))
{
pcsp.AssignedAdmins.Add(admin);
}
}
Trying to execute the line pcsp.AssignedAdmins.Add(admin), I get the error:
Error: The relationship between the two objects cannot be defined
because they are attached to different ObjectContext objects.
There is one context for the class and it comes from Dependency Injection (the class is a Service in an MVC app).
I've tried removing/attaching and so on, but this doesn't fix it - it just gives different error messages. It's not even obvious which entity is using another context.
Any ideas of where this other context the error message refers to is coming from?
See The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
Where has admin come from?
Getting the admin object from the same context as the pcsp object should help.
Sorted it, but it was quite a major refactor.
The issue was that each service received it's own instance of 'context', so when two entities from two services were expected to work together, they wouldn't as each belonged to a different context.
One solution would have been to make the class that created the context a 'Singleton' so that it always returned the same instance, but that would have been very BAD as every page would then use the same context.
Each service got it's own instance of 'context' through Dependency Injection.
I changed the project so only the controllers got an instance of context through DI. Then, in the controller constructor, this context was passed to the services that the controller had received through dependency injection.
This way, each request only ever uses a single instance of context, but this instance is still short lived, as it is supposed to be as each request has its own context and doesn't share one.
Not sure this is the way it is supposed to work, but given the web app I was working with, this seemed to be the best solution.
I also had to go through and add a 'context.SaveChanges();' statement everywhere a change to the database was made.
Not sure why this should be when the old version of EF did this automatically, but it now works.
Thanks for the advice Derrick
I'm using breezejs with an entity framework 5 model. The model is the old-school edmx/objectcontext style- not the newer dbcontext/poco style.
The model is shared with some wcf ria services domain services so I cannot switch to entity framework 6 or poco style entity framework at this time.
When using wcf ria services, if you wanted to add a property to an entity beyond what is generated by entity framework you could create a partial class, define the property and annotate it with the datamember attribute. Wcf ria services treats this new property like any other property and sends it to the client from the server and back to the server.
Is there a way to do the same thing with breezejs? Without moving entirely away from the automatic metadata generation goodness that comes with using entity framework?
Using fiddler I can see the property I want exposed is transmitted to the client during a query request.
I've looked at the documentation here http://www.breezejs.com/documentation/extending-entities but none of the examples seem to fit this scenario.
Breeze supports unmapped properties, these are properties that are declared on your javascript constructor that cannot be matched to any property in metadata. By default these properties are both persisted locally and sent to the server on a save. This is described in the link you mentioned:
http://www.breezejs.com/documentation/extending-entities
var Customer = function () {
this.myUnmappedProperty = "anything22";
};
myEntityManager.metadataStore.registerEntityTypeCtor("Customer", Customer);
These values will be available on the server after a SaveChanges call via the 'UnmappedValuesMap' property on each EntityInfo instance.
var unmappedValue = entityInfo.UnmappedValuesMap["myUnmappedProperty"];
What is sounds like you are looking for is "unmapped" properties to go in the "other" direction, i.e. from the server to the client. What might work for that but we haven't tried is adding a property to your server side EF class ( via the partial class mechanism) and mark it up for Json serialization. It "should" then get serialized down to the client, even though it won't show up in Metadata.
If this does NOT work, please post back here and we will consider it as a breeze feature request. The basic idea does make a lot of sense and we should support it.
Has anyone else tried using the server-side component of Breeze.js in a solution with multiple Api Controllers for multiple EF Models?
I'm finding that after calling the MetaData endpoint on one context, all subsequent calls to MetaData endpoints in other contexts return the MetaData from the first context which was called, for example say I have two Api Controllers, each with their own MetaData endpoint:
public class CoreController : ApiController
{
readonly EFContextProvider<CoreEntities> contextProvider = new EFContextProvider<CoreEntities>();
}
public class FormsController : ApiController
{
readonly EFContextProvider<FormsEntities> contextProvider = new EFContextProvider<FormsEntities>();
}
Calling ~/Core/MetaData will return the JSON for the Core model, however a subsequent call to ~/Forms/MetaData will not return the Forms JSON, but instead the Core metadata is returned. If I call them in reverse I get the Forms metadata both times, this issue appears to persist until the host process is recycled.
I can confirm that I am able to access object data from both models as expected, so I doubt this is a routing issue.
Perhaps someone can tell me if there is some caching going on somewhere which I need to disable?
Regards,
Tom Tregenna
Ok, this should be fixed in Breeze 0.73.4, available either via nuget or zips on the breeze website.
You are right. I've tested this issue and this behaviour you reported happened. Putting breakpoints for each Metadata() method for the two Controllers, and using Fiddler, I concluded that this is not a routing issue. The two Controllers are using differents Context (contextProvider's property), but the first Metadata that was called is always returned. I guess this is Breeze's library issue. I've read the Breeze's documentation, but I have not found anything that could help.
There is another issue with the same symptoms. It is related to ambiguous references to the Entity Framework metadata in the connection string. I had two separate EDMX files, both of which were named Model.edmx (separate projects). When I referenced the assembly that contained the second EDMX file, the connection string below became ambiguous - the metadata files from both of the EDMX files fit the description.
metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;
I was able to resolve the issue by renaming one of the EDMX files.
An alternative solution would be to replace the asterisk with the full name of the assembly which contains the embedded metadata - there is actually a performance benefit to doing so. See the MSDN documentation covering Entity Framework connection strings for further details.
assemblyFullName
The full name of an assembly with the embedded resource. The name
includes the simple name, version name, supported culture, and public
key, as follows:
ResourceLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Resources can be embedded in any assembly that is accessible by the
application.
If you specify a wildcard (*) for assemblyFullName, the Entity
Framework runtime will search for resources in the following
locations, in this order:
The calling assembly.
The referenced assemblies.
The assemblies in the bin directory of an application.
If the files are not in one of these locations, an exception will be
thrown.
Cc716756.note(en-us,VS.100).gifNote: When you use wildcard (*), the
Entity Framework has to look through all the assemblies for resources
with the correct name. To improve performance, specify the assembly
name instead of the wildcard.
Context:
Code First, Entity Framework 4.3.1;
User ---- Topic, 1 to Many relation;
User with public virtual ICollection<Topic> CreatedTopics Navigation Property(Lazy Loading);
Topic with public virtual User Creator Navigation Property;
DataServiceController : DbDataController<DefaultDbContext>, Web API beta, ASP.NET MVC 4 Beta , Single Page Application;
System.Json for Json serialization;
Web API Action:
public IQueryable<Topic> GetTopics()
{
// return DbContext.Topics; // OK
return DbContext.Topics.Include("Creator"); //With Exception
}
Result: "an unhandled microsoft .net framework exception occurred in w3wp.exe"
The Problem here seems to be: I should not Add Navigation Property in both Entities(Cause Circular Reference?), and if I delete the CreatedTopics Navigation Property in User Class, It will be OK again.
So, In a similar Context like listed above, Here are my questions:
How to deal with Navigation Properties in the situation of 1 to Many relation;
Further more, how about a Many to Many relation, do i have to divide it into two 1 to Many relations;
What is the Best Practices and Precautions of using Navigation Properties?
I Have read many related posts, but still not clear enough :(,
Thanks for any help!
Dean
This is not a problem of code first or EF - it is a problem of serialization. Simply the serializer used to convert your object graph to some representation passed in a Web API message is not able to work with circular references by default. Depending on the message format you want to use Web API uses different serializers by default - here is more about default serializers used by Web API and about the way how to change it. The following text suppose that you are using DataContractJsonSerializer or DataContractSerializer (should be default for XML serialization) but the same is possible for JSON.NET (should be default for JSON serialization - JSON serialization can be switched to DataContractJsonSerializer but the default serializer is better).
So what you can do? You can tell the serializer that it should track those circular references by marking your classes with DataContract(IsReference = true) and each passed property with DataMember attribute (check the linked article for description how to achieve it with JSON.NET). This will allow serializer correctly recognizing cycles and the serialization will in theory succeed. In theory because this also demands to not using lazy loading. Otherwise you can serialize much more data than you expected (in some catastrophic scenarios it can lead to serializing whole content of your database).
When you serialize entity graph with lazy loading enabled you serailze a Topic and its Creator but serialization will also visit CreatedTopics property => all related topics are lazy loaded and processed by serialization and serialization continues to visit Creator of all newly loaded topics! This process continues until there is no other object to lazy load. Because of this you should never use lazy loading when serializing entities.
Other option is to exclude back reference from serialization. You just need to serialize Creator. You don't need to serialize CreatedTopics so you can mark the property with IgnoreDataMember attribute (JsonIgnore for JSON.NET). The problem is that if you also have Web API action for returning User with all his CreateTopics this will not work because of the attribute.
The last option is not using entities. This option is usually used in web services where you create special DTO objects satisfying requirements for specific operation and you handle conversion between entities and DTOs inside the operation (possible with help of some tool like AutoMapper).
There is no difference between handling one-to-one, one-to-many, or many-to-many relations. If you have navigation properties on both sides you must always deal with this problem.
I have two databases that I am accessing. The first is against a contact database which I connected to using EF Model First; creating the edmx. I have since begun to learn the virtue of CODE First when working with Entity Framework, so I decided I would, in the same project, write the Product database using Code First techniques, allowing the database to be generated from the code I am writing.
Everything compiles fine. The problem occurs when I hit my harness and it attempts to create the Product database and retreive a list of values from one of the tables...
I get the folowing error "Could not find the conceptual model type for 'Core.Data.Account'", when I attempt to enumerate the ProductLines property (Line3 below).
1. using (var ctx = new ProductDb())
2. {
3. var lines = ctx.ProductLines.ToList();
4. this.litOne.Text = lines.Count.ToString();
5. }
After some research it appears that this message may be occuring because of multiple entities with the same name (regardless of namespace), however there is nothing in the ProductDb context with the name "Account".
There is a class in the OTHER context created by the Model First approach named "Account". But how/why would that make a difference? They each point to different databases i.e. different connection strings. Why would the ProductDb be attempting to create a table called Account, when it should be completely unaware of it's exstence?
thoughts?
Thank you as always!,
- G
I bumped into the same problem, but the other way around: first a DbContext + generated database and then generated an edmx off the database (just for a little presentation). It appeared to be a restriction in EF: EF currently has a restriction that POCO classes can't be loaded from an assembly that contains classes with the EF attributes.
The only thing you can do for now is keep the contexts in separate assemblies.