db4o: how can we get the data for only one object? - db4o

How can DB4o users get back the data for only one object?
(This is akin to getting the data for only one row of a traditional relational database table.)
With DB4o, I only know how to get the data back for a class of objects but not simply one unique object instance.

just query objects and get first item out of the result (the same like in relational database)
to get it by Guid ID:
using (IObjectContainer session = this.GetNewSession())
{
Dummy result = (from Dummy item in session
where item.Id == Guid.Parse("....")
select item).FirstOrDefault()
}
the result will be either null if item doesn't exist or the object found
other option is to get it directly by internal ID such as (or even UUID):
long id = ....;
using (IObjectContainer session = this.GetNewSession())
{
Dummy result = (Dummy)session.Ext().GetByID(id);
}

I have answered my own question (I believe):
Solution #1:
public List<Object> getListOfObjects(final Object o){
List<Object> result = db.query(new Predicate<Object>(){
#Override
public boolean match (Object arg0){
if(arg0.equals(o)){
return true;
}
else{
return false;
}
});
return result;
}
Solution #2:
public ObjectSet<Class<?>> getListOfObjects(Object o){
Query q = db.query();
q.constrain(o);
ObjectSet<Class<?>> set = q.execute();
return set;
}
Maybe someone knows if one of these solutions is better than the other, or whatever.

Related

Edit operation not saving to the DB

I posted the question earlier, but didn't receive any correct responses, hence posting again with some edits. I have a function that accepts two parameters, IDs and Dates. When I had put breakpoints, I was able to see the Ids and the Dates selected on the page as parameter values. However, after hitting the process button, nothing happens, meaning this data isn't getting saved to the DB.
Model Classes:
public class Hello{
public string ID{ get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime? Date{ get; set; }
}
Controller Class:
[HttpGet]
public ActionResult Selection(string ids, string dates)
{
model = new Hello();
ExtensionDB db = new ExtensionDB();
string[] IDS = ids.Split(',');
string[] DATES = dates.Split(',');
List<Hello> list = new List<Hello>();
for (int i = 0; i < IDS.Length; i++)
{
if (IDS[i] != null && IDS[i] != "")
{
Hello item = new Hello { ID = IDS[i], Date = DateTime.Parse(DATES[i]) };
list.Add(item);
}
}
if (ModelState.IsValid)
{
foreach (var row in db.Table1)
{
foreach (var row2 in db.Table2)
{
if (row.UID== row2.CID) // UID and CID are Foreign keys that join these two tables
{
foreach (var item in list)
{
if (row.UID == Convert.ToInt32(item.ID))
{
row2.ReportedDate = item.Date;
}
db.SaveChanges();
}
}
}
}
ViewBag.Message = "Success";
return View(model);
}
else
{
ViewBag.Message = "Failed";
return View(model);
}
}
I will add the view class if needed, however the problem is here.. You can also refer to it here: Saving changes to the DB MVC
Your code does not attempt to update anything. Start with confirming what the data you are passing to this POST call contains, and what you want to do with it. It looks like what you are trying to do is update the dates for a number of records. Looking at your previous post (no need to re-post another question with the same code) there are a few things..
First: Structure the data you want to pass to the POST call into a collection of simple objects containing an id and a date. For example:
{
id = rid,
date = date
}
and add those to the collection named something like "updateData" rather than two separate arrays of IDs and dates. Then in the server-side code, declare a simple view model class:
public class UpdateDateViewModel
{
public int Id { get; set; }
public DateTime Date { get; set; }
}
In the ajax call instead of:
data: { ids: ids, dates: dates },
you'll want something like:
data: { updates: updateData },
where updateData is your collection of id + date pairs.
and use that view model in your method:
public ActionResult Process(IList updates)
Provided that request data is sent as Json, ASP.Net should translate that data automatically for you, though you may need to configure ASP.Net to translate the camelCase vs PascalCase. Worst case, to test, you can use camelCase property names ("id" and "date")
Now when it comes to updating the data: Server side, please get in the habit of using meaningful variable names, not "c", "i", etc. It makes code a lot easier to understand.
public ActionResult Process(IList<UpdateDateViewModel> updates)
{
using (db = new DB())
{
//rp = new RequestProcess(); - Assuming RequestProcess is an Entity?
//var c = rp.getStuff(); - No idea what this getStuff() method does...
foreach(var update in updates)
{
var request = db.RequestProcesses.Find(update.Id);
if (request != null)
request.RequestDate = update.Date; // If we find a matching request, update it's date.
else
{ // Doesn't exist, create it and add it to the DbSet.(table)
var request = new RequestProcess { Id = update.Id, RequestDate = update.Date };
db.RequestProcesses.Add(request);
}
db.SaveChanges();
}
}
}
Now this is a very bare bones guess at what you may be trying to do. Ideally though, updates should be completely separate from adds in the sense that an update should only deal with existing records. If it comes across an ID that it cannot find it should throw an error, ignore, and/or return a status to the user that something wasn't right. Creating new entries should be a separate call and ensure that records are properly initialized with their required fields.
Your original code looked to be taking a list of IDs, but then creating a new entity and calling that "getStuff" method that didn't have the DbContext, or any of the values from the POST call, but then attempting to copy values from that entity into the string parameters that you passed (which would overwrite the Json string) None of that would have updated an entity which would never have updated your data.
Take it slow and follow the examples before attempting to adapt them to your ideas. It will be a lot more constructive and less frustrating then writing a bunch of code that doesn't really make much sense, then wondering why it doesn't work. Your original code has probably a dozen or more problems and inefficiencies. Simply pasting it up on Stack will get a lot of confusing comments based on these problems which don't really help with the first issue you want to solve. Strip it back to the minimum, start with getting the data you need to the server in a meaningful way, then from that, attempt to use that data to update your entities.

Best Way to Update only modified fields with Entity Framework

Currently I am doing like this:
For Example:
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
db.Entry(oldobj).CurrentValues.SetValues(model);
}
It works, but for example,
I have 50 columns in my table but I displayed only 25 fields in my form (I need to partially update my table, with remaining 25 column retain same old value)
I know it can be achieve by "mapping columns one by one" or by creating "hidden fields for those remaining 25 columns".
Just wondering is there any elegant way to do this with less effort and optimal performance?
This is a very good question. By default I have found that as long as change tracking is enabled (it is by default unless you turn it off), Entity Framework will do a good job of applying to the database only what you ask it to change.
So if you only change 1 field against the object and then call SaveChanges(), EF will only update that 1 field when you call SaveChanges().
The problem here is that when you map a view model into an entity object, all of the values get overwritten. Here is my way of handling this:
In this example, you have a single entity called Person:
Person
======
Id - int
FirstName - varchar
Surname - varchar
Dob - smalldatetime
Now let's say we want to create a view model which will only update Dob, and leave all other fields exactly how they are, here is how I do that.
First, create a view model:
public class PersonDobVm
{
public int Id { get; set; }
public DateTime Dob { get; set; }
public void MapToModel(Person p)
{
p.Dob = Dob;
}
}
Now write the code roughly as follows (you'll have to alter it to match your context name etc):
DataContext db = new DataContext();
Person p = db.People.FirstOrDefault();
// you would have this posted in, but we are creating it here just for illustration
var vm = new PersonDobVm
{
Id = p.Id, // the Id you want to update
Dob = new DateTime(2015, 1, 1) // the new DOB for that row
};
vm.MapToModel(p);
db.SaveChanges();
The MapToModel method could be even more complicated and do all kinds of additional checks before assigning the view model fields to the entity object.
Anyway, the result when SaveChanges is called is the following SQL:
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Dob] = #0
WHERE ([Id] = #1)
',N'#0 datetime2(7),#1 int',#0='2015-01-01 00:00:00',#1=1
So you can clearly see, Entity Framework has not attempted to update any other fields - just the Dob field.
I know in your example you want to avoid coding each assignment by hand, but I think this is the best way. You tuck it all away in your VM so it does not litter your main code, and this way you can cater for specific needs (i.e. composite types in there, data validation, etc). The other option is to use an AutoMapper, but I do not think they are safe. If you use an AutoMapper and spelt "Dob" as "Doob" in your VM, it would not map "Doob" to "Dob", nor would it tell you about it! It would fail silently, the user would think everything was ok, but the change would not be saved.
Whereas if you spelt "Dob" as "Doob" in your VM, the compiler will alert you that the MapToModel() is referencing "Dob" but you only have a property in your VM called "Doob".
I hope this helps you.
I swear by EntityFramework.Extended. Nuget Link
It lets you write:
db.Person
.Where(x => x.ID == model.ID)
.Update(p => new Person()
{
Name = newName,
EditCount = p.EditCount+1
});
Which is very clearly translated into SQL.
Please try this way
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
// Newly Inserted Code
var UpdatedObj = (Person) Entity.CheckUpdateObject(oldobj, model);
db.Entry(oldobj).CurrentValues.SetValues(UpdatedObj);
}
public static object CheckUpdateObject(object originalObj, object updateObj)
{
foreach (var property in updateObj.GetType().GetProperties())
{
if (property.GetValue(updateObj, null) == null)
{
property.SetValue(updateObj,originalObj.GetType().GetProperty(property.Name)
.GetValue(originalObj, null));
}
}
return updateObj;
}
I have solved my Issue by using FormCollection to list out used element in form, and only change those columns in database.
I have provided my code sample below; Great if it can help someone else
// Here
// collection = FormCollection from Post
// model = View Model for Person
var result = db.Person.Where(x => x.ID == model.ID).SingleOrDefault();
if (result != null)
{
List<string> formcollist = new List<string>();
foreach (var key in collection.ToArray<string>())
{
// Here apply your filter code to remove system properties if any
formcollist.Add(key);
}
foreach (var prop in result.GetType().GetProperties())
{
if( formcollist.Contains(prop.Name))
{
prop.SetValue(result, model.GetType().GetProperty(prop.Name).GetValue(model, null));
}
}
db.SaveChanges();
}
I still didn't find a nice solution for my problem, so I created a work around. When loading the Entity, I directly make a copy of it and name it entityInit. When saving the Entity, I compare the both to see, what really was changed. All the unchanged Properties, I set to unchanged and fill them with the Database-Values. This was necessary for my Entities without Tracking:
// load entity without tracking
var entityWithoutTracking = Context.Person.AsNoTracking().FirstOrDefault(x => x.ID == _entity.ID);
var entityInit = CopyEntity(entityWithoutTracking);
// do business logic and change entity
entityWithoutTracking.surname = newValue;
// for saving, find entity in context
var entity = Context.Person.FirstOrDefault(x => x.ID == _entity.ID);
var entry = Context.Entry(entity);
entry.CurrentValues.SetValues(entityWithoutTracking);
entry.State = EntityState.Modified;
// get List of all changed properties (in my case these are all existing properties, including those which shouldn't have changed)
var changedPropertiesList = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList();
foreach (var checkProperty in changedPropertiesList)
{
try
{
var p1 = entityWithoutTracking.GetType().GetProperty(checkProperty).GetValue(entityWithoutTracking);
var p2 = entityInit.GetType().GetProperty(checkProperty).GetValue(entityInit);
if ((p1 == null && p2 == null) || p1.Equals(p2))
{
entry.Property(checkProperty).CurrentValue = entry.Property(checkProperty).OriginalValue; // restore DB-Value
entry.Property(checkProperty).IsModified = false; // throws Exception for Primary Keys
}
} catch(Exception) { }
}
Context.SaveChanges(); // only surname will be updated
This is way I did it, assuming the new object has more columns to update that the one we want to keep.
if (theClass.ClassId == 0)
{
theClass.CreatedOn = DateTime.Now;
context.theClasses.Add(theClass);
}
else {
var currentClass = context.theClasses.Where(c => c.ClassId == theClass.ClassId)
.Select(c => new TheClasses {
CreatedOn = c.CreatedOn
// Add here others fields you want to keep as the original record
}).FirstOrDefault();
theClass.CreatedOn = currentClass.CreatedOn;
// The new class will replace the current, all fields
context.theClasses.Add(theClass);
context.Entry(theClass).State = EntityState.Modified;
}
context.SaveChanges();
In EF you can do like this
var result = db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
if(result != null){
result.Name = newName;
result.DOB = newDOB;
db.Person.Update(result);
}
Or you can use
using (var db= new MyDbContext())
{
var result= db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
result.Name= newName;
result.DOB = newDOB;
db.Update(result);
db.SaveChanges();
}
For more detail please EntityFramework Core - Update Only One Field
No Worry guys
Just write raw sql query
db.Database.ExecuteSqlCommand("Update Person set Name='"+_entity.Name+"' where Id = " + _entity.ID + "");

Two checks IValidatableObject in one entity

Is the essence of Project, the creation of which is necessary to check whether there is already an entity with the same name. When editing needs such as checking, but keep in mind that the old and the new name of the entity can be matched.
You also need to display an error message. For this I use interface IValidatableObject, but do not know how to tell the Validate method the object is currently being edited or created
DbContext.ValidateEntity takes the IDictionary<Object, Object> items as the second parameter. You can pass any data there and the data you pass will be passed to IValidatableObject.Validate in the ValidationContext.Items
Assuming you refer to check EF cant do for you.
This is actually difficult to check. You are checking an entity after it has been added to the context. It should not check itself and needs to consider other items in context that are not yet saved. As well as the DB. There are several 3 combinations plus an self recognition. Record a an entity record in LOCAL when ID is blank/new ie multiple new inserts needs careful coding. (Consider using temp IDs)
the not yet saved entries should be in context
Context.Set<TPoco>().Local
and get data from DB and keep in a temp list. BUT dont put in context.
Or use a SECOND context.
var matchingSet = Context.Set<TPoco>().AsNoTracking() // not into context...
.Where(t=>t.field == somevalue).ToList();
So what about logical and actual duplicates on the DB. Logical duplicates are duplicates on a field with no unique index that from a business perspective should be unique.
If you want to check those...
You need to read the DB.... BUT if these records are currently being changed, you CAN NOT just put them into the Context. You would overwrite them.
But what if the values the logical key values have changed?
Something caused a logical dup on a record on the DB may no longer be a dup once saved or vice verse. Is that still a dup or not ?
So you need to decide how you match LOCAL versus loaded records.
Ie check LOCAL and matching DB records and decidr what to do if a record is in both, only local or only db.
LOCAL ONLY and DB Only is easy.
But in both... That is your business process decision.
Problem is solved using method ModelState.AddModelError (string, string) in actions Edit and Create.
[HttpPost]
[HandleError(View="AjaxError")]
public ActionResult Edit(ProjectsViewData data)
{
if (ModelState.IsValid)
{
if (!ContainsProject(data.CurrentObject.Name))
{
db.Projects.Attach(data.CurrentObject);
db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
db.SaveChanges();
return Projects(data);
}
else
{
int projectId = (from p in db.Projects
where p.Name == data.CurrentObject.Name
select p.ProjectID).FirstOrDefault();
if (projectId == data.CurrentObject.ProjectID)
{
db.Projects.Attach(data.CurrentObject);
db.ObjectStateManager.ChangeObjectState(data.CurrentObject, EntityState.Modified);
db.SaveChanges();
return Projects(data);
}
else
{
ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
}
}
}
data.ObjectToEdit = data.CurrentObject;
return Projects(data);
}
[HttpPost]
[HandleError(View = "AjaxError")]
public ActionResult Create(ProjectsViewData data)
{
if (ModelState.IsValid)
{
if (!ContainsProject(data.CurrentObject.Name))
{
db.Projects.AddObject(data.CurrentObject);
db.SaveChanges();
return Projects(data);
}
else
{
ModelState.AddModelError("Name", Localizer.ProjectAlreadyExists);
}
}
data.ObjectToAdd = data.CurrentObject;
return Projects(data);
}
Helper method:
private bool ContainsProject(string projectName)
{
if (projectName != null)
{
projectName = Regex.Replace(projectName.Trim(), "\\s+", " ");
List<string> projects = new List<string>();
var projectNames = (from p in db.Projects
select p.Name.Trim()).ToList();
foreach (string p in projectNames)
{
projects.Add(Regex.Replace(p, "\\s+", " "));
}
if (projects.Contains(projectName))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}

what's the best practice to attach a entity object which is detached from anthoer ObjectContext?

As mentioned in the title, how many methods are available?
I just have this case: I get a entity object from one ObjectContext, and then I detach the entity obejct from OjbectContext object, and return it.
Later, if I make some changes on this object, and I want to save the changes back to database. I think I should write like this, right? (Well, this works for me.)
public Url GetOneUrl()
{
Url u;
using(ServicesEntities ctx = new ServicesEntities())
{
u = (from t in ctx.Urls select t).FirstOrDefault<Url>();
ctx.Detach(u);
}
return u;
}
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
ctx.Detach(t);
ctx.Attach(url);
ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
ctx.SaveChanges();
}
}
Url url = GetOneUrl();
url.UrsString = "http://google.com"; //I just change the content.
SaveToDB(url);
OR
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url;
t = url; //this will make t.UrlString becomes "http://google.com"
ctx.ApplyCurrentValues<Url>("Urls", t);
ctx.SaveChanges();
}
}
This way is also works for me.
The first way will generate sql statement to update all the columns of Url table, but the second method will provide a sql script only update the "UrlString" Columns.
Both of them will have to retrieve a temp entity object from database which is the 't' in above code.
Are there any other methods to achieve this purpose? Or other better method you know about it? Or any official solution about this topic?
Many Thanks.
I don't understand your first example. Why do you first get entity from ObjectContext? It is not needed because you have just created new instance of the context. You can just use:
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
ctx.Attach(url);
ctx.ObjectStateManager.ChangeObjectState(url, System.Data.EntityState.Modified);
ctx.SaveChanges();
}
}
In your second example you can just call:
public void SaveToDB(Url url)
{
using(ServicesEntities ctx = new ServicesEntities())
{
var t = ctx.GetObjectByKey(_Url.EntityKey) as Url; // Ensures that old values are loaded
ctx.ApplyCurrentValues<Url>("Urls", url);
ctx.SaveChanges();
}
}
Now the difference between two approaches is clear. First approach (Attach) does not need to query the DB first. Second approach (ApplyCurrentValues) needs to query the DB first to get old values.
You can use two additional approaches. First is just extension of your former approach. It allows you defining which properties were changed. Second approach is manual synchronization with loaded entity. This approach doesn't use any special methods. You will simply set loaded entity's properties to required values manually. This approach is useful if you work with object graph instead of single entity because EF is not able to automatically synchronize changes in relations.

Json and Circular Reference Exception

I have an object which has a circular reference to another object. Given the relationship between these objects this is the right design.
To Illustrate
Machine => Customer => Machine
As is expected I run into an issue when I try to use Json to serialize a machine or customer object. What I am unsure of is how to resolve this issue as I don't want to break the relationship between the Machine and Customer objects. What are the options for resolving this issue?
Edit
Presently I am using Json method provided by the Controller base class. So the serialization I am doing is as basic as:
Json(machineForm);
Update:
Do not try to use NonSerializedAttribute, as the JavaScriptSerializer apparently ignores it.
Instead, use the ScriptIgnoreAttribute in System.Web.Script.Serialization.
public class Machine
{
public string Customer { get; set; }
// Other members
// ...
}
public class Customer
{
[ScriptIgnore]
public Machine Machine { get; set; } // Parent reference?
// Other members
// ...
}
This way, when you toss a Machine into the Json method, it will traverse the relationship from Machine to Customer but will not try to go back from Customer to Machine.
The relationship is still there for your code to do as it pleases with, but the JavaScriptSerializer (used by the Json method) will ignore it.
I'm answering this despite its age because it is the 3rd result (currently) from Google for "json.encode circular reference" and although I don't agree with the answers (completely) above, in that using the ScriptIgnoreAttribute assumes that you won't anywhere in your code want to traverse the relationship in the other direction for some JSON. I don't believe in locking down your model because of one use case.
It did inspire me to use this simple solution.
Since you're working in a View in MVC, you have the Model and you want to simply assign the Model to the ViewData.Model within your controller, go ahead and use a LINQ query within your View to flatten the data nicely removing the offending circular reference for the particular JSON you want like this:
var jsonMachines = from m in machineForm
select new { m.X, m.Y, // other Machine properties you desire
Customer = new { m.Customer.Id, m.Customer.Name, // other Customer properties you desire
}};
return Json(jsonMachines);
Or if the Machine -> Customer relationship is 1..* -> * then try:
var jsonMachines = from m in machineForm
select new { m.X, m.Y, // other machine properties you desire
Customers = new List<Customer>(
(from c in m.Customers
select new Customer()
{
Id = c.Id,
Name = c.Name,
// Other Customer properties you desire
}).Cast<Customer>())
};
return Json(jsonMachines);
Based on txl's answer you have to
disable lazy loading and proxy creation and you can use the normal methods to get your data.
Example:
//Retrieve Items with Json:
public JsonResult Search(string id = "")
{
db.Configuration.LazyLoadingEnabled = false;
db.Configuration.ProxyCreationEnabled = false;
var res = db.Table.Where(a => a.Name.Contains(id)).Take(8);
return Json(res, JsonRequestBehavior.AllowGet);
}
Use to have the same problem. I have created a simple extension method, that "flattens" L2E objects into an IDictionary. An IDictionary is serialized correctly by the JavaScriptSerializer. The resulting Json is the same as directly serializing the object.
Since I limit the level of serialization, circular references are avoided. It also will not include 1->n linked tables (Entitysets).
private static IDictionary<string, object> JsonFlatten(object data, int maxLevel, int currLevel) {
var result = new Dictionary<string, object>();
var myType = data.GetType();
var myAssembly = myType.Assembly;
var props = myType.GetProperties();
foreach (var prop in props) {
// Remove EntityKey etc.
if (prop.Name.StartsWith("Entity")) {
continue;
}
if (prop.Name.EndsWith("Reference")) {
continue;
}
// Do not include lookups to linked tables
Type typeOfProp = prop.PropertyType;
if (typeOfProp.Name.StartsWith("EntityCollection")) {
continue;
}
// If the type is from my assembly == custom type
// include it, but flattened
if (typeOfProp.Assembly == myAssembly) {
if (currLevel < maxLevel) {
result.Add(prop.Name, JsonFlatten(prop.GetValue(data, null), maxLevel, currLevel + 1));
}
} else {
result.Add(prop.Name, prop.GetValue(data, null));
}
}
return result;
}
public static IDictionary<string, object> JsonFlatten(this Controller controller, object data, int maxLevel = 2) {
return JsonFlatten(data, maxLevel, 1);
}
My Action method looks like this:
public JsonResult AsJson(int id) {
var data = Find(id);
var result = this.JsonFlatten(data);
return Json(result, JsonRequestBehavior.AllowGet);
}
In the Entity Framework version 4, there is an option available: ObjectContextOptions.LazyLoadingEnabled
Setting it to false should avoid the 'circular reference' issue. However, you will have to explicitly load the navigation properties that you want to include.
see: http://msdn.microsoft.com/en-us/library/bb896272.aspx
Since, to my knowledge, you cannot serialize object references, but only copies you could try employing a bit of a dirty hack that goes something like this:
Customer should serialize its Machine reference as the machine's id
When you deserialize the json code you can then run a simple function on top of it that transforms those id's into proper references.
You need to decide which is the "root" object. Say the machine is the root, then the customer is a sub-object of machine. When you serialise machine, it will serialise the customer as a sub-object in the JSON, and when the customer is serialised, it will NOT serialise it's back-reference to the machine. When your code deserialises the machine, it will deserialise the machine's customer sub-object and reinstate the back-reference from the customer to the machine.
Most serialisation libraries provide some kind of hook to modify how deserialisation is performed for each class. You'd need to use that hook to modify deserialisation for the machine class to reinstate the backreference in the machine's customer. Exactly what that hook is depends on the JSON library you are using.
I've had the same problem this week as well, and could not use anonymous types because I needed to implement an interface asking for a List<MyType>. After making a diagram showing all relationships with navigability, I found out that MyType had a bidirectional relationship with MyObject which caused this circular reference, since they both saved each other.
After deciding that MyObject did not really need to know MyType, and thereby making it a unidirectional relationship this problem was solved.
What I have done is a bit radical, but I don't need the property, which makes the nasty circular-reference-causing error, so I have set it to null before serializing.
SessionTickets result = GetTicketsSession();
foreach(var r in result.Tickets)
{
r.TicketTypes = null; //those two were creating the problem
r.SelectedTicketType = null;
}
return Json(result);
If you really need your properties, you can create a viewmodel which does not hold circular references, but maybe keeps some Id of the important element, that you could use later for restoring the original value.

Resources