Storing complex types in Entity Framework - asp.net-mvc

I have created a database using the edmx designer in an ASP.NET MVC project. This has a number of tables like this:
An Office can have many Locations
Each Location can have many Staff
Each Location has Location Type
Each Location has a Business Type
Each Location has a Browser Version
Each Browser Version has a Browser
The details of this are probably unimportant. The core class is Staff, it has a Location property, which has an Office property, a LocationType property, a BusinessType property and a Browser Version property (which has the Browser property).
I'm creating a registration form. I started by trying to create a Staff member instance to save by using code like staffMember.Location.LocationType = DB.Locations(l => l.Id = model.Id);
which populated the class with fully populated class instances. Calling the save method at this point would blow up with :
Entities in 'DBContainer.BrowserVersions' participate in the
'BrowserBrowserVersion' relationship. 0 related 'Browsers' were found.
1 'Browsers' is expected.
Now, again, the BrowserVersion.Browser class was correctly populated.
So, I did some reading, and as a result I made sure my code always uses the same DBContext. This did not fix my issue. So I changed my code to do something like this:
staffMember.Location.BrowserType = new BrowserType { Id = myBrowserType.Id };
This would then blow up with an error like :
{"Cannot insert the value NULL into column 'BrowserName', table
'MyProject.dbo.Browsers'; column does not allow nulls. INSERT
fails.\r\nThe statement has been terminated."}
In the end I found I cannot use the objects copied from my DBContext, but I need to create objects that have all the relevant properties copied across from the objects I get from the DB. Surely I am doing something wrong, I'm writing more code now than if I used stored procs and my own data layer?

Related

In DDD, how to create/edit domain ValueObjects ASP.NET MVC?

We have identified a Location entity in a database as a value object in our domain (DDD). Locations are used by other domain objects, but don't really "stand alone" -- they always belong to another entity.
Now we are trying to edit a list of these values in a simple MVC web application. So the view would show a list of locations in a view model LocationViewModel.
However, the value object is by definition immutable, yet does hold a reference to another entity (Business).
Domain:
public class Location : ValueObject<Location>
{
readonly locationId;
public int LocationId {get{return _locationId;}}
public Business Business {get;set;}
}
My problem is understanding how you can simply edit a bunch of value objects in a UI and change, e.g. what Business the location belongs to.
A value object is not supposed to have an "identity", but it does need an ID so the repository can update the database.
I also don't think you can make Location an entity just because you want to edit it in the UI. Or is Location, in this scenario indeed an Entity?
What am I not understanding?
Thank you!
It's a classic problem. In one context it's an entity and in another a value object. I found the example of a telephone number helpful to understanding this sort of problem.
In a CRM for example, a telephone number is a value object. The same one can be associated with multiple contacts. It varies by value (key concept here). So in this context it's a value object. In this example, I could store telephone numbers in the database and the 'ID' would be the telephone number itself. If the value object was made up of multiple parts then they would form a composite key.
If however we looked at a telephone number at a telephone company. That would most likely be an Entity. It could have all manor of information attached to it. All that info would vary by ID (which in this case would be the number).
In your case, Location sounds like a value object. If you need to save it in a database as a thing rather than just as part of an entity then use it's parts as a composite key. You will need to handle what happens when you 'change' one as it's not a change but the creation of new value object. One approach is to remove the old and insert the new. Or just keep all versions. It depends on your domain.
Hope that's helpful.
You don't change a value object. You create a new one with different values. If the value object has few properties that you want often to change, some helper methods are usefull. myObject.WithX(4711) will create a new instance with all properties the same as myObject but the X Property changed to 4711 for example.
To "edit" a value object in an UI you use a viewmodel. The Viewmodel is not a value object (and no entity by the way) and is not part of your domain. It's purely in the Presentation Layer. It is editable and mutable. It could have a constructor, taking your (immutable) value object to copy its values from and it could have a ToXXX Method to create a new (immutable) value object with its current (and changed) values.
If you want to store your value objects in a separate table (instead of roll out the fields in the table that stores the owning entity) this is purely data access layer related and not part of your domain model. This could be done by mapping. In the value object the database id is immutable and has no meaning in the domain model.

Using breeze.js I only want to send updated properties for a non-cached entity

I have a scenario where I know the primary key of an entity (retrieved from an unrelated source), and I want to update just 1 property (db column). I have NOT already retrieved the entity from the database. If possible I would like to not have to make this extra round trip.
I create the entity using manager.createEntity.
I update one of the properties.
Then set the entityAspect to setModified();
When saving changes, all the properties that were not updated are set to their default values, and the generated SQL UPDATE statement attempts to update all mapped columns.
Is there a way to tell breeze to only generate SQL for specific properties/columns?
thanks
As you discovered, the properties of the originalValuesMap guide the Breeze server's ContextProvider as it prepares the save request. This is documented in the ContextProvider topic.
In your example, you call setModified after you've changed the property. All that does is change the EntityState; it doesn't create an entry in the client entity's entityAspect.originalValuesMap ... therefore the originalValuesMap sent to the server is empty.
I'm a little surprised that the EFContextProvider.SaveChanges prepared an EF update of the entire entity. I would have guessed that it simply ignored the entity all together. I'm making a mental note to investigate that myself. Not saying the behavior is "right" or "wrong".
You do not have to manipulate the originalValuesMap to achieve your goal. Just change the sequence. Try this:
var foo = manager.createEntity('Foo', {
id = targetId
}, breeze.EntityState.Unchanged); // create as if freshly queried
foo.bar = 'new value'; // also sets 'originalValues' and changes the EntityState
manager.saveChanges(); // etc.
Let us know if that does the trick.

how to get the default values from the model into a new breeze clientside entity

i would like to create new entities which use the default values defined in the model.
i've checked the retrieved metadata, and the default values are there:
{"name":"LastName","type":"Edm.String","maxLength":"50","unicode":"true","fixedLength":"false","defaultValue":"admin:
Nachname"},
however they are not taken into consideration when creating a new entity.
This is a bug in Breeze that should be fixed in the next release, out in about week. When this fix gets in then breeze will honor any defaultValues it finds in the EntityFramework data model.
One problem though is while it is easy to get 'defaultValues' into a Model First Entity Framework model via the properties editor, it's actually difficult to get it into a Code First EF model, unless you use fluent configuration. Unfortunately, EF ignores the [DefaultValue] attribute when constructing Code First model metadata.
One workaround that you can use now is to poke the 'defaultValue' directly onto any dataProperty. Something like:
var customerType = myEntityManager.metadataStore.getEntityType("Customer");
var fooProperty = customerType.getProperty("foo");
fooProperty.defaultValue = 123;

Performance implications : Entity table reference vs List of that table reference

I am using entity framework and developing an architecture for application with remote data access. Coming back to point, i query the database for one record (say on the basis of itemcode). Now the resultset i will get whether i should return it as List or collection or simple as an object of entity. I am using entity object but my boss is saying i should use List. He thought , returning result as an entity with return whole table structure also. Quick suggestion would be appreciated.
List<Employee> lstemployee = GetRecordByCode(itemCode)
or
Employee emp = GetRecordByCode(itemCode)
What's the difference? If itemCode is a unique key you will either get one Employee object or a list containing the same one Employee object. You will never return the whole table. That will only happen if within GetRecordByCode you do something like context.Employees.ToList() without any Where filter before the ToList().
If itemCode is not unique you even have to use a list.

Code First and Model First in the same project?

I have two databases that I am accessing. The first is against a contact database which I connected to using EF Model First; creating the edmx. I have since begun to learn the virtue of CODE First when working with Entity Framework, so I decided I would, in the same project, write the Product database using Code First techniques, allowing the database to be generated from the code I am writing.
Everything compiles fine. The problem occurs when I hit my harness and it attempts to create the Product database and retreive a list of values from one of the tables...
I get the folowing error "Could not find the conceptual model type for 'Core.Data.Account'", when I attempt to enumerate the ProductLines property (Line3 below).
1. using (var ctx = new ProductDb())
2. {
3. var lines = ctx.ProductLines.ToList();
4. this.litOne.Text = lines.Count.ToString();
5. }
After some research it appears that this message may be occuring because of multiple entities with the same name (regardless of namespace), however there is nothing in the ProductDb context with the name "Account".
There is a class in the OTHER context created by the Model First approach named "Account". But how/why would that make a difference? They each point to different databases i.e. different connection strings. Why would the ProductDb be attempting to create a table called Account, when it should be completely unaware of it's exstence?
thoughts?
Thank you as always!,
- G
I bumped into the same problem, but the other way around: first a DbContext + generated database and then generated an edmx off the database (just for a little presentation). It appeared to be a restriction in EF: EF currently has a restriction that POCO classes can't be loaded from an assembly that contains classes with the EF attributes.
The only thing you can do for now is keep the contexts in separate assemblies.

Resources