Update Navigation Properties - entity-framework

I am a newbie to Entity framework and I was confused when i want to update an existing Entity with Navigation Property.
Here is an Model class I am using.
public class Institution
{
[Key]
public int ID { get; set; }
public int Code { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Key { get; set; }
public string PreferURL { get; set; }
public virtual ICollection<EntitlementEntity> Entitlement{ get; set; }
}
I did an MVC HttpPost back in the edit action with auto deserialization from SCOTT HANSELMAN(http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx).
Everything works fine if I ignore Navigation PropertiesICollection<EntitlementEntity> Entitlement in the form; once included, an exception throw.
{"An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same key."}
I finally got it work as below.
https://gist.github.com/pwang2/8363266
What i am reluctant to do is we already have all the relations in the original Institution Entity with Navigation Property, but here I have to set the institution relation for every Entitlement Entity again.
My questions are:
Is it possible to update the institution entity as well as its Navigation Properties at the same time.
If not, what's the best practice if I want a more concentrate UI result to allow update both the institutional information and its entitlement at the same time?

Related

EF creating an unwanted field in database

I've hit a snag while building a .net mvc site. I have 2 related objects and am struggling with properly linking them. Specifically:
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostCode { get; set; }
[ForeignKey("AddressCategory")] // <-- EF adds field to below object's table
public int AddressCategoryId { get; set; }
public virtual AddressCategory AddressCategory { get; set; }
}
public class AddressCategory
{
public int AddressCategoryId { get; set; }
public string Description { get; set; }
}
Adding the [ForeignKey] data annotation to the Address object results in EF adding an Address_AddressId column to the AddressCategory table, which I don't want (or need) to happen.
I've tried to omit the ForeignKey attribute, but then I run into other errors because .net can't link the tables (e.g. Unknown column 'Extent1.AddressId' in 'field list'). Additionally, I wouldn't be able to use:
var addresses = db.Addresses.Include(l => l.AddressCategory);
Is there any way to link the 2 tables without EF adding an additional column to the AddressCategory table?
Thank you to #cloudikka for responding. After much trial-and-error I seem to have gotten it to work simply by omitting any ForeignKey reference from either object. I let EF rebuild the database and perform all scaffolding (CRUD forms) and they have been created perfectly.
My take-away is that foreign key attributes should be used for parent-child relationships, but not for look-up tables. I clearly have much to learn about asp.net mvc!

Is this expected Entity Framework 7 / Core behaviour or a bug?

I have a simple model for the purposes of this post.
Two entities Role and Person.
public class Role : Entity
{
public Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Person> PeopleWithThisRole { get; set; }
}
public class Person : Entity
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Guid? RoleId { get; set; }
}
If I get the Roles from the EF context, then the PeopleWithThisRole collection is empty (unless I .Include them. As expected.
However if I get the Roles and I then get the People as below
var roles = _context.Roles.ToList();
var people = _context.People.ToList();
Then roles.PeopleWithThisRole collection is fully populated with the people without having to .Include it.
Is this the expected behaviour or should I raise this as a bug?
Thanks
UPDATE
With many thanks to #hvd below, I have decided to keep the entities clean and not use [JsonIgnore] attribute and instead map to DTOS (which exclude those properties I don't need in the JSON) - which is probably the correct way!
It's expected and also how earlier versions of EF worked.
Your _context keeps track of entities loaded inside that context, to allow for saving changes. Inside that context, Person objects have been loaded (at your request) and their RoleId values are known. Inside that same context, Role objects with those same Id values have been loaded (also at your request). EF links the objects in memory based on those IDs. If you trace the SQL queries sent to the server, you should find that no queries have been sent other than those that you requested.

Why MVC does autoupdate of EF Model Classes?

I generated Entity Model from my database in my MVC5 App.
When I try to add [DispalyName] to some properties it works fine, but after some time app refreshes this class by itself and removes all my custom code
public partial class Patient
{
public Patient()
{
this.PatientDetails = new HashSet<PatientDetail>();
}
public int PatientID { get; set; }
[DisplayName("Last Name")]
public string LastName { get; set; }
public string FirstName { get; set; }
public virtual ICollection<PatientDetail> PatientDetails { get; set; }
}
Why MVC does it and how to disable that?
I believe since you're using Database first, the entities will get completely re-created every time you refresh, thus you lose your custom attributes.
Also, to go off of Joe's comment, you should make a view model and put your [Display] attributes there and not directly on the entity.

Entity Framework Code first missing foreign key entities in WebAPI project

I'm afraid that if I include my code this post will get too long and too complicated, so I'll try and explain my problem. If however you'd like to see some code illustrating this problem, I'll be happy to add it afterwards.
I have a project, MVC4 project (Website.Web) that used entity framework code first. My entity classes is in a seperate project: Website.Domain
I have a NewsPost class:
public virtual int Id { get; set; }
public virtual string Subject { get; set; }
public virtual string Content { get; set; }
public virtual string ImageName { get; set; }
public virtual DateTime CreateTime { get; set; }
public virtual int CreatedById { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
And my comments class looks like this:
public virtual int Id { get; set; }
public virtual int CreatedById { get; set; }
public virtual DateTime CreatedTime { get; set; }
public virtual string Content { get; set; }
Now in my MVC project, I have entity framework set up with some repository classes and ninject to seperate everything from my controllers. And when I do a "GetAll()" on my newsposts. The NewsPost.Comments will be filled with the comments that's associated with this newspost. It all works perfectly.
Now I got the idea that I'd like to use webapi, so I set up a new MVC basic project. I removed the views folder, and removed the models folder. Then I setup all the repositories here as well along with my entity framework dbcontext class. And enabled migrations on the project to allow me to use entity framework code first in the same fasion as the Website.Web project. I also referenced the same Domain classes as the web project.
Now here comes the problems. I tried doing a GetAll() on the newsposts, but when I inspect the list returned by GetAll(), I see that though it fetches all the news in the database, the COMMENTS are null. I'm pretty sure I have the Website.API set up the same way as my Website.Website.Web - So what am I missing?
I hope I have explained well enough. Again if you need any additional code or I need to clarify some points, I'll happily do this, I just didn't wanna make the question more complicated than it already is with too much code.

Serialize one to many relationships in Json.net

I am using the Entity Framework code first for data access and I have a Company class which has a collection of Employees. The Employee class also has a Company property.
I would like to be able to serialize a Company and include the list of employees in the serialization.
Here is Company:
public class Company
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime? Established { get; set; }
public virtual IList<Employee> Employees { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateUpdated { get; set; }
}
Here is Employee
public class Employee
{
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public virtual Company Company { get; set; }
public DateTime? DateCreated { get; set; }
public DateTime? DateUpdated { get; set; }
}
I get a serialization Exception "Self referencing loop detected for type" when I try to serialize a Company object.
Thanks.
I think they have fixed this in the latest version.
Check out the help docs under the section "Serializing and Deserializing JSON -> Serialization and Preserving Object References".
Set this setting when initializing the JSON.Net Serializer:
PreserveReferencesHandling = PreserveReferencesHandling.Objects;
So an example would be this:
var serializerSettings = new JsonSerializerSettings { PreserveReferencesHandling = PreserveReferencesHandling.Objects };
string json = JsonConvert.SerializeObject(people, Formatting.Indented, serializerSettings);
I verified that this works with my code first solution, and a circular reference in the navigation properties. If you look at the resulting JSON it should have "$id" and "$ref" properties everywhere.
Updated Answer
You can either:
reconfigure json.net to ignore
selfreference loops
use the [JsonIgnore] Attribute
use a custom converter that remove
the navigation in the child
or you can use Data Transfer Objects
In case this helps anyone, I thought I'd document how we resolved this same error for our purposes when using Entity Framework 4.3.1 and JSON.Net 4.5.3.
We are using the Database First DbContext approach. For our needs, we could resolve it using the [JsonIgnore] attribute. The trick is just that since changes to the automatically generated entity classes are overwritten when you refresh from the database, with Database First you can add the attributes using the "metadata buddy class" approach given in this StackOverflow post.
Below is a code excerpt. We had a "Query" object (class Query) that had relationships to "Company" and "User" objects. In a new class file, we declare the partial class with a [MetadataType] attribute, and then in the QueryMetadata class we specified, we annotate the members we want to ignore— namely the public virtual members that EF4.x adds to express the relationships (a.k.a. navigation properties).
The Query entity also has foreign key fields (named FK_User and FK_Company in our case). These fields do not need the [JsonIgnore] attribute— they can be serialized with their foreign key values.
[MetadataType(typeof(QueryMetadata))]
public partial class Query
{
}
public class QueryMetadata
{
[JsonIgnore]
public virtual Company company { get; set; }
[JsonIgnore]
public virtual User user { get; set; }
}
However, if we actually had to also serialize the related Company or User objects, we'd hit a brick wall! The approach suggested by John Bubriski here wouldn't work for us since we want to rely on Entity Framework change tracking.
If you are getting this error using WebApi you can put the following in WebApiConfig.cs so json.net ignores circular refs
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
Microsoft : Loop Reference handling in Web API
If you're using WebAPI EntityFrameworkCore 2.0 this solution doesn't work, you need to set it on Startup.cs->ConfigureServices:
.AddJsonOptions(options => {
var settings = options.SerializerSettings;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});