1

I am building a ASP.NET webapplication and I am also working with Entity Framework Code First. In this case I am using two entities (Customer and Contact) which have a One-to-Many relation with eachother (one Customer can have multiple Contacts). While getting the data from the database, everything goes fine. I also use Viewmodels, so next to my data entities, I also have two models called CustomerModel and ContactModel.

Below here I will show my entities and my viewmodels:

Customer-entity

[Table("Customer")]
    public class Customer
    {
        [Key()]
        public Guid Id { get; set; }
        //other non-relevant properties
        public virtual List<Contact> Contacts { get; set; }
    }

Contact-entity

[Table("Contact")]
    public class Contact
    {
        [Key()]
        public Guid Id { get; set; }
        //non-relevant properties
        [ForeignKey("Customer")]
        public Guid CustomerId { get; set; }
        [Required]
        public virtual Customer Customer { get; set; }
    }

CustomerModel

[Serializable]
    public class CustomerModel
    {
        public Guid Id { get; set; }
        //non-relevant properties
        [ScriptIgnore(ApplyToOverrides = true)]
        public virtual List<ContactModel> Contacts { get; set; }
    }

ContactModel

[Serializable]
    public class ContactModel
    {
        public Guid Id { get; set; }
        //non-relevant properties
        public Guid CustomerId { get; set; }
        [ScriptIgnore(ApplyToOverrides = true)]
        public virtual CustomerModel Customer { get; set; }
    }

When I run my application and the code as well, it all works fine in the backend until it needs to serialize it to JSON in my HomeController.

public ActionResult GetCustomerById(Guid id)
        {
            CustomerModel customer = new CustomerManager().GetById(id);
            string output = serializer.Serialize(customer);
            return Content(output);
        }

Even the CustomerModel object gets the 2 contacts, but at my Serialize(customer) method, it doesn't parse it to JSON. So actually, when I debug it and look at my output, I see every property but not the nested ContactModels.

In my case the string output doesn't contain the two Contacts. How do I solve this? I have checked some 'similar' questions on Stackoverflow as well but with no result.

6
  • 1
    Well first of all, don't serialize entities (that's why you have the database, make your own structure to serialize (read up on Data Transfer Object (DTO))). second of all. by serializing stuff like this you will get circular references. meaning A referring B referring A (loops to infinity), that's why you have to stop following references, in most cases stopping the references in either the many link or one link will do the trick, in some cases you must block off both. This means that yes you will kindof "miss" some data. There is a limit to complexity on JSON that's not in SQL Commented Apr 17, 2016 at 9:56
  • @ThomasAndreèLian so if I understand your answer right, it might help if I construct my viewmodels in another way without references to store my properties in a correct way. Commented Apr 17, 2016 at 10:03
  • Are you claiming CustomerModel and ContactModel are view models? If they were, they would not have [Serializable] or [ScriptIgnore] attributes and the properties would not be virtual. Apart from the circular reference issue (remove CustomerModel Customer), if you want to return Json, the use return Json(customer); Commented Apr 17, 2016 at 10:05
  • yes, remove all serializing in your entities, they never belong there. (it's a bad path to start) Commented Apr 17, 2016 at 10:05
  • @ThomasAndreèLian thank you, also in my viewmodels? Or just in my database-entities called 'Customer' and 'Contact'? Commented Apr 17, 2016 at 10:06

1 Answer 1

1

Okay, i see you are missing a concept DTO and circular refferencing, in simplicity you must make a model of the content you want to deliver. What's biting you is layers/refferences, so I did away with all the loopyness in our models.

Think of a -> b -> a that whould result in a json looking something like this

{ a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a:b{a}}}}}}}}}} //Into infinity and beyond }

This is in essence what you want.

public JsonResult GetCustomerById(Guid id)
{
    CustomerModel customer = new CustomerManager().GetById(id);
    CustomerResultModel output = new CustomerResultModel(){
        id = customer.Id,
        Contacts = GetContacts(customer.Contacts)
    };
    return Json(output, JsonRequestBehavior.AllowGet); 
    //If you only POST then remove the AllowGet (the action name says Get so I'm assuming
}
private IEnumerable<ContactResultModel> GetContacts(Contacts){
    foreach(var a in Contacts){
        //When you use the yield keyword in a statement, you indicate that the method, operator, or get accessor in which it appears is an iterator.
        yield return new ContactResultModel(){            
            Id  = a.Id,
            CustomerId = a.CustomerId
        };
    }
}

Models

class CustomerResultModel{
    public Guid id {get;set;}
    public IEnumerable<ContactResultModel> Contacts {get;set;}
}

class ContactResultModel{
    public Guid id {get;set;}
    public Guid CustomerId {get;set;}
}
Sign up to request clarification or add additional context in comments.

6 Comments

I am trying this out atm, I will answer asap when I get the results
and ofc if you need more data in the result model you add that, just dont do circular refferences in your DTO like you are allowed to do in your entities (many-one)
It finally worked out for me, but not with the example you gave me. I tried to understand the DTO indeed and it helped me to avoid the circular refference stuff. But the only change I made, was deleting the CustomerId and CustomerModel property inside my ContactModel class and also the deleted [ScriptIgnore(ApplyToOverrides = true)] above the public virtual List<ContactModel> Contacts { get; set; } property.
After doing this, it works fine and also serializes the nested ContactModel entities inside my CustomerModel object. Thank you for your help Thomas!
thats prettymuch the same, as my models (they are the same as you gave but without the linked propps) as i mention sometimes you can get away with removing only one of the directions
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.