Saving Dropdown list selection with Entity Framework in ASP.NET MVC solution - entity-framework

I'm looking for advice on a decent pattern for dropdown list selection and persistence of the selection with POCO EF please.
I have a list of IEnumerable<Country> in my view model where Country is a POCO loaded via EF. There is an Address property on the view model that takes the current or user selected value on it's Country property. Within the view I display these via a Html.DropdownListFor() thus:
Html.DropDownListFor(model => model.Address.Country.Id, new SelectList(Model.Countries,"Id","Name",model.Address.Country.Id)
So far so good and it all works on postback with the default ModelBinder providing me with a view model with the Address.Country populated. However Address.Country is of course only populated with the Id field with default model binding.
Trying to send the Address update back to the DB through EF blows up as this is seen as a new object which doesn't have it's full object graph loaded, only the Id set.
Now I can fix this by loading the full Country object from the db into the Address.Country property on postback before saving based on the selected Id. But this seems like a lot of hard work for anything beyond a simple object graph.
The most "elegant" solution I could think of would be a custom model binder for Country but then that would require the Model Binder to know about the repository for retrieving the full EF object which doesn't seem right to me. I'd also have to repeat this for all other Entities used in Dropdown lists.
Hope this makes sense and any feedback on how others are doing this would be appreciated.

If you set Address.Country to an object, EF expects it to be a full object that's part of the current context, but EF does recognize foreign keys: If your Address object has both a CountryID property and a Country property, it should accept Address.CountryID being set as long as Address.Country itself is null.

In your Address class declare country as virtual
public class Address
{
public virtual Country Country;
}
try this and let me know if it works, Virtual supports lazyloading and you don't have to query explicitly

Related

EF and OData entity relationships - need some basic help bad

I have what I think is a very basic problem. Created an OData web server to serve up Customers and Orders. Each order has a relationship to a Customer. Code snippet is:
public class Customer
{
int Id {get;set;}
...
}
public class Order
{
int Id {get;set;}
public virtual Customer customer {get;set;}
...
}
When the web service creates the db and tables, it all looks good. If I add a Order object (in the orders controller) with the customer object set correctly, the generated Customer_Id foreign key field gets filled in. My problems are:
On the client, when I add an order to the OData container, it does not serialize the customer object so the controller gets a null value. When I set the customer object in the controller, EF seems to handle the process fine putting in the right Id for that customer.
Am wondering if I need a .AddLink call on the client app. If so, not sure what to add as all my attempts throw exceptions.
container.AddLink(order.Customer,"Customer",order); (throws exception that order does not have a settable property)
When I try and retrieve an order object, the customer object is always null. I have disabled LazyLoading and even have a .Include(o=>o.Customer) in the orders controller get handler.
Think I am missing something pretty basic, just not getting what I need to do to make this work. I do have an embedded complex type that is working as expected, just can't get the entity relationships to flow in the client.
Thanks for any help you can provide.

Entity Framework (6.x), Computed Columns and INotify

I'm using a DB First implementation of Entity Framework and I've run into an issue with a need for a computed column and the interaction with a view...
Scenario:
User has FirstName and LastName. In a listbox I want to use a display name generated from FirstName and LastName. Generally, simple enough. The issue comes from when either the first name or last name gets edited. I've extended my entities with INotifyPropertyChanged and implemented that in the T4 template. I extended the User entity to create a DisplayName property. In the View I use a CollectionViewSouorce based on the DisplayName.
The issue comes in when a user's name is edited, but no notification occurs because the change is made to either FirstName or LastName, not DisplayName. So the CollectionViewSource is never getting a change notification for DisplayName.
I could, manually, add an OnPropertyChanged("DisplayName") to the User entity in the FirstName and LastName properties, but that would be overwritten next time I update my model from the DB.
Any ideas on how to make this work?
Thanks.
J
I'd go for one of the following options:
create partial class User to your User entity with OnFirstNameChanged,OnLastNameChanged methods implemented in it, the class remains unchanged when you re-generate classes from model.
handle context.ObjectStateManager.ObjectStateManagerChanged event of your ObjectContext
http://msdn.microsoft.com/en-us/library/system.data.objects.objectstatemanager%28v=vs.100%29.aspx
adjust the t4 template(based on your question you know how to deal with it) to call custom method when FirstName and LastName property setter is generated.
For the record...
I went with a partial class extension and just programmatically triggered OnPropertyChanged for the DisplayName whenever the constituent properties were changed and saved.

How to make an Entity Framework property NOT NULL, but not required in form submission

I'm using Entity Framework 4.1 with a code-first model. A common pattern is that many objects reference the user who owns them, eg.
public class Item
{
public User Owner { get; set; }
}
This creates a nullable column in the DB, but since every Item must have an owner I want the column marked NOT NULL. If I use the [Required] attribute then submitting the form to create an Item results in an error. That field is never set through a form, only manually in code.
It is generally recommended to create separate view models for such situations. Using database models as view models for input forms is seen as an anti-pattern.
Make a ItemViewModel that has the same properties as Item and relevant data validation attributes. You may want to use a library called Automapper to automate the boring property-copy-code needed in those cases.

Cascade eager-loading problem

Supose I have following entities created from database tables:
Person
Student
Student include Person as navigation property.
Person has navigation property Country to connect lookup table Country.
In Student metadata, I do put [Include] for navigation property Person.
In Person metadata, I do put [Include] for navigation property Country.
When loading student data, I want to eager loading like to include Person and Country data:
this.ObjectContext.Students.Include("Person").Include("Country");
This was working fine when I use previous version of ASP.NET Data Ria Service. Now when it is changed to WCF Ria Service, above way not working any more.
System give me the error said Country is not a navigation property of Student.
How to resolve this problem?
The error is correct.
Include is on the ObjectQuery<T> you are querying, in this case "Students".
Country is a navigational property of Person, not Student.
Change your code to this:
this.ObjectContext.Students.Include("Person").Include("Person.Country");
Or simply:
this.ObjectContext.Students.Include("Person.Country");
As EF will automatically include "Person" based on the nested include.
You need to remember that Include returns an ObjectQuery<T> based on the ObjectQuery<T> it was invoked upon.
So just because your doing Students.Include("Person"), that doesn't mean at that point, the variable is ObjectQuery<Person> - the variable is still ObjectQuery<Student>.

Entity Framework/.Net 4.0: POCO and saving many to one relationships

How do I have to set up a property so that when using SaveChanges, the many to one relationship is saved and I don't get the: INSERT statement conflicted with the FOREIGN KEY constraint... error.
Pretty simple, I have an Ad and an AdType where there are many Ads to one AdType. There is a property on Ad:
public class Ad
{
public Int32 AdTypeId { get; set; }
public virtual AdType AdType { get; set; }
}
To cover this relationship.
When I do this:
someAd.AdType = someAdType;
The property is set just fine, but the AdTypeId is not. No worries though since I would assume this would be ok to save.
context.SaveChanges();
Problem is at this point it is trying to save the 0 value in the AdTypeId column (Causing a foreign key issue) instead of using the object assigned AdType property to figure out what it should insert into the AdTypeId column.
Things I know:
At this point someAdType is
persisted/has an id.
The AdType property is set correctly.
The AdTypeId is 0.
There is a foreign key relationshipin the database.
AdTypeId is a primary key.
I have deferred/lazy loading set to true
I haven't really tried changing the AdType since it is set up to allow lazy loading.
Ok looks like because I am using the non proxied (Made that word up... Yah) "Snapshot based Change Tracking" approach, the system has no real idea that it's changed.
In this example, Customer is a pure
POCO type. Unlike with EntityObject or
IPOCO based entities, making changes
to the entity doesn’t automatically
keep the state manager in sync because
there is no automatic notification
between your pure POCO entities and
the Entity Framework. Therefore, upon
querying the state manager, it thinks
that the customer object state is
Unchanged even though we have
explicitly made a change to one of the
properties on the entity.
Got that from here
So in order to make sure it knows to check to see if there has been a change I have to use the AcceptAllChangesAfterSave option with the SaveChanges method.
context.SaveChanges(System.Data.Objects.SaveOptions.AcceptAllChangesAfterSave);
And it works. Hopefully I understand it correctly...