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.
Related
Is it possible to reference additional columns apart from the 'Code' and 'Name' columns when using a domain attribute in an entity?
E.g. A person entity has a code of '1' and a name of 'Smith' and a Gender of 'Male'
In a customer entity there is a domain value referencing the person entity which displays the following 1 {Smith}. The users would like an additional read only attribute which would copy the Gender value of 'Male' into the customer entity based on the domain value. Can this be done using out of the box MDS UI?
I know this is duplicate data and breaks normal form but for usability this would be useful. It would be the equivalent of referencing additional columns in an MS Access drop down list.
Many thanks in advance for any help
This is not possible with the standard UI. One option would be to develop a custom UI where you can handle these kind of requests.
If you want to stick with the standard product I can see a workaround but this is a bit of a "dirty" one.
You can misuse (abuse) the Name attribute of the Person entity by adding a business rule to the Person entity that generates the content of the Name attribute as a concatenation of multiple attributes. You of course need an additional attribute that serves as a place holder for the original Name. The concatenated field will then show in your customer entity.
One question that does come to mind is why a user would like/need to see the gender of a person in a customer list? As you have a separate Person entity I expect you to have multiple persons per customers. What would the gender of one person - even if it is the main contact - matter?
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.
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>.
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
We've started using Entity Framework 4 for data access and have come across an issue or perhaps lack of understanding.
Our current system is heavily reliant on Stored Procedures, these procedure contain some necessary business logic so we need to continue to use these when doing Select/Insert/Update/Delete.
The issue we are having is the following:
We've mapped a table to an entity, let's say for example this is a User entity and has the following properties - UserId, FirstName, LastName
Now in our sproc to insert a user we accept FirstName, LastName, CreatedById as parameters.
As our User Entity has no CreatedById we get an error indicating that no property of our Entity can be mapped to the "CreatedById" parameter.
Now one thing we've tried is to manually add a CreatedById scalar property to our Entity, but this results in the issue that there is no Field in our User table in the data source that maps to CreatedById. In general the additional property that we'd like to pass in is not something that is stored.
Now there is potential solution to this in that we can just map the procedures to Function Imports and not bother with using the .AddObject, .DeleteObject, .SaveChanges way of manipulating our objects but that doesn't feel like the way to go about it.
that's a good question. There are few options i can tell u.
instead of mapping the entity to the table, map it a view and have the view return CreatedById and then your problem would be solved.
Second option is to create overloaded stored procedure that takes only FirstName, LastName and calls the actual stored procedure with a default value for CreatedById. You can create overloads at the database layer or create it in the model in the ssdl layer which supports inline stored procedure.
exec myproc #firstName,#LastName,null