I have a breeze controller that accepts a JObject, is there an easy way to deserialize that JObject into it's strongly typed source EntityInfo objet without going through Save changes / Before Save changes. I just want to get the object that the JObject payload is referring to.
Thanks for your help.
I ended up using the approach outlined in this related question.
Uninitialised JsonSerializer in Breeze SaveBundleToSaveMap sample
Option 1
Take a look at the code in the Breeze.ContextProvider class's CreateEntityInfoFromJson method. It's protected-internal so you'll need to copy the code or call it using reflection. Use at your own risk.
Option 2
The breeze savechanges code uses a public class called SaveWorkState which is constructed using two arguments: a ContextProvider and a JArray. To get an idea of what's expected for the
JArray, take a look at the "entities" property in the JSON sent to the server during a savechanges.
Once the SaveWorkState is constructed you can access the EntityInfo objects via the EntityInfoGroups property.
I've never tried either option before, found these options by looking at the breeze.server.net code.
Yes it is possible ... and pretty easy too. I answered this question in GREAT detail on the related SO question, Uninitialised JsonSerializer in Breeze SaveBundleToSaveMap sample that you referenced.
Related
After struggling for a while, in order to protect my model while style enjoying Breeze metadata, I finally created a second DbContext just for the metadata. That's the one passed to EFContextProvider. So I have one DbContext for the model, and one that serves as a data access layer, with dto's.
After that I've tried hard to use automapper to automap in linq projections, but kept hitting the wall with a null reference exception. However, this library: http://linqprojector.codeplex.com/ that's related and uses the exact same syntax, works perfectly.
Now, I have a method on my server that actually returns what I want: a dto, containing a list.
So say I have a class Blog containing a list of Posts in the model. The method returns an object BlogDTO containing a list of PostsDTO.
BUT, in Breeze, in the BlogDTO object, the array of posts stays empty. I witness with my own eyes the data being sent to the browser, but for some reason, Breeze ignores some of it!
Honestly, there really are quite a few problems to solve going down this path.
Just wanted to share it with you guys. If anyone understands this and can help me. Here's the Breeze query:
var query = EntityQuery
.from('BlogWithPosts')
.withParameters({id: blogId});
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
console.log(data);
var s = data.results[0];
return blogObservable(s);
}
So to be clear, in the object data, in the XHR property, the responseText property holds all the data that I want! Do I have to parse it myself? What was the point of getting my metadata down to breeze then...
Ok I finally figured this one out. Apparently Breeze requires the InverseProperty attribute. Once that has been set, I could see my related entities!
Other important element to take into account: avoid circular references in your classes. Otherwise Breeze might just simply ignore related entities, for all I know.
Are there any entity.property documentation 'field' in breeze?
For example, on an entity.property in EntityFramework are two documentation properties: Long Description and Summary. I can see those two properties in metadata on client side but I am wondering if any of those properties are used in breeze.
Analyzing the breeze.debug.js I didn't notice any usage of those or similar properties but maybe somebody have an idea how to use them (extract from metadata) and attach them for example to an entity instance. Or maybe somebody have some similar solution.
This is a good idea!. Please add this to the breeze User Voice. We take these suggestions very seriously. Hopefully we can also get out some documentation describing how to intercept the metadata retrieval process so that you can add your own logic to do this.
As a stopgap, the MetadataStore.fetchMetadata method currently does return ( in its promise 'then' method) the the raw "metadata" retrieved from the server. So for now, you could plumb this and pick out these properties and attach them directly to each corresponding breeze dataProperty.
Note that by the time the fetchMetadata method returns the entire MetadataStore will have already been populated with entityTypes, dataProperties, navigationProperties, etc. This makes the task much easier.
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.
Is there a good way to detect when the ObjectContext changes are actually committed?
SavingChanges occurs before going to the data store but I also need a way to know if those changes where actually committed.
Thanks in advance
John
Update:
What I have is a code first DbContext. This is fed into dynamic data which as I discovered uses the DbContext's internal ObjectContext (to which I have access when casting to IObjectContextAdapter). The dbcontext's SaveChanges is not called, the objectcontext's SaveChanges is used instead. All I want to do is to be notified after the save is complete (i.e. event SavedChanges) so I can invalidate my cache.
There is no build-in event to handle this but you can override SaveChanges method in your derived context and fire any custom event specific to your own context type after you call base.SaveChanges.
pardon me, but I can't find the solution in the answer.
Let me rephrase this question according to my understanding (and my case):
I am using Dynamic Data, which ONLY accepts ObjectContext as configuration; if you use DbContext (which is the way to go with Code First) then you will have to pass the property "IObjectContextAdapater.ObjectContext" like the following:
DefaultModel.RegisterContext(() => { return ((IObjectContextAdapter) new MyDbContext()).ObjectContext; }, new ContextConfiguration() { ScaffoldAllTables = true });
The problem here is that when you save changes, the SaveChanges method of the MyDbContext is NOT called, instead Dynamic Data calls the method SaveChanges in the MyDbContext.ObjectContext.
So overriding the SaveChanges in MyDbContext is useless in this case.
How can we access the SaveChanges in the ObjectContext property and change the behavior so we can write our custom code?
But anyway, the solution I found correct was in a comment by "rene" to the question above, which is adding an event handler for SavingChanges EVENT in the ObjectContext property, here is the link again:
http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.savingchanges.aspx
I hope this clears it
This is a little out there but I have a customer object coming back to my controller. I want to just reconnect this object back to the database, is it even possible? I know there is a datacontext.customers.insertonsubmit(customer), but is there the equivalent datacontext.customers.updateonsubmit(customer)???
This is what I don't like about LINQ-to-SQL.
It generally works fine if you're querying and updating in the same scope, but if you get an object, cache it, and then try to update it later, you can't.
Here's what the documentation says:
Use the Attach methods with entities that have been created in one DataContext, and serialized to a client, and then deserialized back with the intention to perform an update or delete operation. Because the new DataContext has no way of tracking what the original values were for a disconnected entity, the client is responsible for supplying those values. In this version of Attach, the entity is assumed to be in its original value state. After calling this method, you can then update its fields, for example with additional data sent from the client.
Do not try to Attach an entity that has not been detached through serialization. Entities that have not been serialized still maintain associations with deferred loaders that can cause unexpected results if the entity becomes tracked by a second data context.
A little ambiguous IMHO, specifically about exactly what it means by "serialized" and "deserialized".
Also, interestingly enough, here's what it says about the DataContext object:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
So, DataContexts are intended to be tightly scoped - and yet to use Attach(), you have to use the same DataContext that queried the object. I'm assuming/hoping we're all completely misunderstanding what Attach() is really intended to be used for.
What I've had to do in situations like this is re-query the object I needed to update to get a fresh copy, and then do the update.
The customer that you post from the form will not have entity keys so may not attach well, also you may not have every field of the customer available on the form so all of it's fields may not be set.
I would recommend using the TryUpdateModel method, in your action you'll have to get the customer from the database again and update it with the form's post variables.
public ActionResult MySaveAction(int id, FormCollection form)
{
Customer updateCustomer = _Repository.GetCustomer(id);
TryUpdateModel(updateCustomer, "Customer", form);
_Repository.Save(updateCustomer);
}
You will have to add in all your own exception handling and validation of course, but that's the general idea.
You want to use the attach method on the customers table on the data context.
datacontext.customers.Attach(customer);
to reconnect it to the data context. Then you can use SubmitChanges() to update the values in the database.
EDIT: This only works with entities that have been detached from the original data context through serialization. If you don't mind the extra call to the database, you can use the idiomatic method in ASP.NET MVC of retrieving the object again and applying your changes via UpdateModel or TryUpdateModel as #Odd suggests.