How do I determine the ID of an aggregate root added to a repository? - asp.net-mvc

Say I have a generic repository interface as follows:
public interface IRepository<T>
{
Add(T item);
Delete(int itemId);
Update(T item);
}
Typically the new ID of an item added through IRepository.Add() would be determined by some back-end database, but only once the overall transaction/unit of work has been submitted. So I'm fairly certain that it would be wrong for IRepository.Add() to return the new ID of the added item. The repository really shouldn't know anything about how ID are created. Is this correct?
If this is a case how else can one determine the new ID of an item added to a repository, or should I even be doing this? I know an ORM like NHibernate is able to automagically replace objects in memory with new objects with the correct ID, but I'm trying to design my repository with out any specific ORM implementation in mind.
For example say I have a website where customers can make orders. A new customer chooses to check out and is sent to a form to fill out their details. This information is used to create a Customer object which is stored in a CustomerRepository. Now their order information needs to be created but an Order needs to reference a Customer by their ID?
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
customerRepository.Add(newCustomer);
//How would I determine customerId??
Order newOrder = new Order(customerId, shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");

In the example you give, I would create the Customer and Order in one step, and pass domain objects to domain objects, instead of passing Ids:
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
// Pass the customer rather than the CustomerId:
Order newOrder = new Order(newCustomer , shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");
customerRepository.Add(newCustomer);
orderRepository.Add(newOrder);
// SaveChanges()
...when the changes are saved, the framework automatically populates the Ids of both Customer and Order, and fills in Customer.Id, Order.customerId, (etc.) by virtue of the Customer object having been assigned to the Order.

Eric,
In the scenario you mention, I don't see any CommitChanges() going on. I would wrap everything in a transactionscope and then hit customerRepository.CommitChanges() before you add the orderlines. you should then be able to grab the id from the newly created customer object and use it as follows:
Order newOrder = new Order(newCustomer.Id, shippingAddress, billingAddress);
then, if the order(s) fails, you can roll everything back and keep it atomic by not hitting scope.Complete().
hope this helps..

I generate id on a client (a la CombGuid.NewGuid()) and then pass it to constructor. Approach when you are using database identity has serious disadvantages

Whether or not you use NHibernate, I feel that the approach it takes is the right one. Your goal with any domain objects is to only ever have one instance of that object in memory at any one time, i.e. you should never have two objects that represent the same database record. It follows that if the database has updated the record with a new id, the domain object in memory should also be updated with that ID since that is the "one" true representation of that record.
After calling Add, the object's ID is set and you could then make further changes to that object and call Update without having to know too much about your implementation.

Your interface is more DAO than Repository according to DDD:
http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/
Like Steve Wilkes mentioned, you should keep reference of Customer in Order and not Customer Id so when Unit of Work is processed, it will create correct link those Entities in Persistence Storage (SQL DB, Web Service etc)
For more on DAO here: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html

Domain entities should have their own ID strategy regardless database IDs, so preferably generate your id in the domain layer, or if you really need to generate id in database, then add another domain identifier generated at domain layer beside the database auto generated id.
In domain driven design where you apply repository pattern you should not tie your domain with database so relying on database for id creation is not a good idea.
Another point is that you may want to make customer associated in order not just putting the customer id, this makes the domain layer rich and solid.

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.

An entity object cannot be referenced by multiple instances of IEntityChangeTracker error when trying to save changes to multiple types of entities

I have a controller action where I am attempting to both create a new object in the database, of type FantasyTeam, and also modify an existing object, of type User. However, when the action is called I am receiving a System.InvalidOperationException exception, with the explanation of:
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker.
My code is below.
public ActionResult Create([Bind(Include="ID,FantasyTeamName")] FantasyTeam fantasyteam)
{
if (ModelState.IsValid)
{
var CurrentUser = UserManager.FindById(User.Identity.GetUserId());
fantasyteam.OwnerID = CurrentUser.Id;
CurrentUser.HasTeam = true;
db.FantasyTeams.Add(fantasyteam);
db.Entry(CurrentUser).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Dashboard", "Application");
}
return View(fantasyteam);
}
The Controller Action takes the new FantasyTeam object as a parameter from the View where the team details are selected by user. I then find the currently logged in user and set the OwnerID of the team to match the UserID of the owner, as my Foreign Key. I then go to add the new FantasyTeam to the database and also modify the User record in the database, changing the Boolean HasTeam to true. The adding of the new team works fine on its own... I have been getting the exception once I tried to modify the User object as well.
I have searched on StackOverflow for this exception, and have found many related issues, but I couldn't find a way to apply the other resolutions to my problem. In some cases the issue was that the developers were using two separate data contexts when they should have just been using one, but I don't think that would apply to me here.
Could someone offer insight as to what might be going wrong here?
Thanks!
According to Linq to SQL DataContext Lifetime Management the main causality of the problem comes from the below reason.
Linq to SQL uses a DataContext to manage it's access to the database as well as tracking changes made to entities retrieved from the database. Linq to SQL has a persistent approach to managing its 'connection' to the database via this data context and it basically assumes that you use a single DataContext to make all of your data related access. This doesn't mean that it makes persistent connections to the database, but means that the DataContext instance maintains state about active result sets, which is especially important if change tracking is on which is the default.
The comment posted by haim770 was the answer - I didn't realize that the UserManager object was using a different context than the db object was using. Once I changed the UserManager object to use the same context as db, my code works as intended.

db4o Impedance Mismatch

I've built a nice repository layer around a db4o database to store Product objects, which relate to Manufacturer objects in a one-to-many relationship, i.e.:
public class Manufacturer
{
public string Name { get; set; }
}
public class Product // simplified
{
public string Name { get; set; }
Manufacturer Manufacturer { get; set; }
}
So far I really like db4o. The problem I have is preventing data duplication without resorting to IDs.
When implementing references like manufacturers using SQL Server, my data models would contain a unique ID field, and in turn my Product class would be dirtied up with a ManufacturerID. I imagined that using an object database like db4o would reduce the impedance mismatch between a relational DB and objects, but without IDs, there is no way to tell one object from another when editing it.
Is there an elegant way to share a manufacturer between products without duplicating data? Or should I just use a relational DB?
You can add an unique index to db4o in your config.
configuration.Common.ObjectClass(typeof (Manufacturer)).ObjectField("<Name>k__BackingField").Indexed(true);
configuration.Add(new UniqueFieldValueConstraint(typeof(Manufacturer), "<Name>k__BackingField"));
This way it is not possible to have two different Manufacturer object with the same name in your db. The field name have to be "k__BackingField"because you are using auto properties. Of course you could add an integer ID, and index it the same way.
The basic things first. db4o manages objects by their object-identity. When you store the same object-instance again, db4o will update that object in the database. The same applies to references. When two different objects refer to the same object, they will actually refer to the same object in the database. In your example: When two different product refer to the same Manufacturer-instance, they will also refer to the same Manufacturer in the database. This is achieved by having a table in the back-ground which keeps track of the objects.
Now this approach has issues. As soon as you serialize objects (web-application, web-services etc), or close the object-container, db4o forgets which object in memory belongs to which object. Then it doesn't recognizes a existing object anymore and just stores is as a new object. This means that you should never load and store a object with different object container instance. And that you probably need IDs to recognizes objects. For example to recognize a object across web-requests. A easy solution is to use Guids to give an unique id to an object.
Back to your question. To share the a manufacturer between products you simply point it to the same manufacturer. Like this:
Product newShinyProduct = new Product(); // the new thing
// Get a existing product or manufacturerer, doesn't matter
Product oldProduct = (from p in container.AsQueryable<Product>()
where p.Name == "Get a product"
select p).First();
// now just assigne the existing manufacturer to the new product
// this product will now refer to the same manufacturer
// and db4o will store this that way. The manufacturer isn't doublicated.
newShinyProduct.Manufacturer = oldProduct.Manufacturer;
// store the new product in the database.
container.Store(newShinyProduct);
db4o does maintain a unique internal ID for each object stored.
check these links:
http://community.versant.com/documentation/reference/db4o-8.1/java/reference/Content/basics/identity_concept.htm
http://community.versant.com/documentation/reference/db4o-8.1/java/reference/Content/platform_specific_issues/disconnected_objects/comparison_of_ids.htm

Should I use nullable types for Id's on my Entity Objects?

My current setup:
I have an entity object with some properties, among them an int Id. To communicate with the database, I've created a repository with, among others, the following method:
public int Add(TEntity entity)
{
ObjectSet.AddObject(entity);
return entity.Id;
}
(It's a generic repository, that requires that TEntity is a class, and that it implements IEntity, which is just an interface with an int Id property.)
My problem:
Now, when I want to create a new entity for adding to the repository, I need to give it an id. However, that doesn't allow EF to automatically generate the id for me, since it will already have a value.
Possible solutions:
I have only been able to think of these two possibilities.
Make the Id property nullable
Pass an EntryInputModel to the repository instead, and then do the mapping there.
Currently I'm binding to EntryInputModel in my Controller, and mapping it to an Entry using AutoMapper. If I need to change this, I also need to re-think the dependencies in my project, since the ...InputModel and ...ViewModel classes are currently only available to my Web application.
Which is preferable? Are there more ways to counter this?
If you're using SQL Server as the backend, my recommended solution would be to make the ID column an INT IDENTITY on the database, and a not-nullable column in your entity object.
When adding a new entity, assign the ID some arbitrary value, like -1 or something, or no value at all, even. The actual ID will be generated automatically by SQL Server when you insert the new entity (
EntityContext.AddToEntities(newEntity);
EntityContext.SaveChanges();
and it will be automagically be signalled back to EF so you'll be able to use it right away once it's inserted:
int newEntityID = newEntity.ID;
Works like a charm - at least in my test apps :-)
you can have generated unique id's that are not generated by the datastore/EF, allowing you to define them before passing the object into EF... (think of Guid's)

Entity Framework creating new record instead of modifying existing one

I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.

Resources