Related Entity

Jul 14, 2014 at 8:45 PM
I would like to create and save an entity with a 1 to many relationship but it doesn't seem to save the many part:
public class Order {
    public int Id { get; set; }
    pubic decimal TaxRate { get; set; }
}
public class OrderLine {
    public int Id { get; set; }
    public int OrderId { get; set; }
    pubic stringProductTitle { get; set; }
}

var order = new Order();
order.TaxRate= 1.20;

order.OrderLines.Add(new OrderLine {OrderId = Order.Id , ProductTitle = "Test"})
order.OrderLines.Add(new OrderLine {OrderId = Order.Id ,ProductTitle = "Test Two"})

_orderService.Add(order);
_unitOfWork.Save();
Error is: A referential integrity constraint violation occurred: The property value(s) of 'Order.Id' on one end of a relationship do not match the property value(s) of 'OrderLine.OrderId' on the other end.

Am I going about this the correct way please?

Thx
Jul 14, 2014 at 10:33 PM
Edited Jul 14, 2014 at 10:33 PM
I'll add an integration test for this one, will update this thread once it's committed.
Jul 14, 2014 at 11:04 PM
Thank you for your quick response
Jul 15, 2014 at 4:55 PM
Marked as answer by lelong37 on 7/15/2014 at 8:55 AM
Jul 19, 2014 at 5:04 PM
Many thanks for the change set example. It work great in your example if you only add one order (or in my example above one OrderLine). However if you try to add two OrderLines I get the error:

Attaching an entity of type 'Swanky.Entities.Models.OrderLine' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.

Any pointers please?

Thx
Jul 20, 2014 at 8:09 AM
Please see change set: http://genericunitofworkandrepositories.codeplex.com/SourceControl/changeset/147eace44e1a4168e661e3a972ae62b2e31e8458.

I've added integration test for Insert, Update and Deleting objects in a graph with multiple child items collections, re-download, I've renamed InsertGraph to a more intuitive name InsertOrUpdateGraph.
Jul 20, 2014 at 10:22 PM
Edited Jul 20, 2014 at 10:29 PM
Thx works great!!!
Btw you didn't add InsertOrUpdateGraph to your service pattern.

Thx
Jul 21, 2014 at 4:02 AM

Make sure you download the latest version. I am passing in a CustomerID but the OrderId is still generated on the database.

Sent using CloudMagic

Aug 4, 2014 at 11:38 PM
I've added an issue which stems from the same problem as in this thread.

I've since found that if I don't set the ObjectState property on my new entity to ObjectState.Added, before calling Repository.InsertOrUpdateGraph(entity), nothing really happens upon UoW.SaveChanges(), because Repository.InsertOrUpdateGraph(entity) does not set that property on the entity, unlike the Repository.Insert(entity) which does set it.

It's a bit of a burden to push that responsibility to the consumer of a Repository method named Insert, as it seems obvious that I'd want the entity's state to be "Added" if I am inserting a new entity record.

Also, in the Service class, when you call Service.InsertGraph(entity), it still calls into Repository.Insert(entity), and not the new Repository.InsertOrUpdateGraph(entity). Is that a bug?

I feel like this framework started out clean and had great intentions, but now it has become a bit convoluted for the sake of being "flexible". It is rather confusing to know which is the right way to use these "patterns" when there are so many ways to get at the same thing (UoW, Repositories, etc.)
Aug 5, 2014 at 12:36 AM

1. You will need to set the ObjectState for every entity on the object graph when using InsertOrUpdate graph (previously named UpdateGraph). This is the only way for the framework to know what you want done for each entities in the graph. The framework also supports managing states while disconnected from the DataContext with repositories and ObjectState is how this is possible.

2. Service not calling the correct InsertOrUpdateGraph is indeed a bug, will release a hot fix for this, thanks for posting this.

3. The only method that requires ObjectState to be set is really the InsertOrUpdateGraph, with the others (e.g. Insert, Update, Delete) we set them since we know the intent by which method you are using and because we are only dealing with one entity. However a) we recommend that you set the ObjectState regardless, of what method you are calling so that teams don't have to question "when do I need to set the ObjectState?".

In terms of the intent of the framework from where it started, all items discussed here have been in the framework since v1 and have actually not changed.


Aug 5, 2014 at 12:41 AM
Aug 5, 2014 at 1:50 AM
Thanks for the clarification.

It would be helpful to provide a test to show sample code for adding a new entity that sets a navigation property from an existing entity, for both 1:1 and 1:0..1 scenarios. Especially in cases when we may expose the FK properties along with the navigation property.

The integration test you provided deals with inserting a graph with 1:M where all entities are new (added), which is not exactly the same scenario I have, but is the same as the OP.

Example:
public class Address {
 public int Id { get; set; }
 public int StateId { get; set; }
 public State State {get;set; }
}

public class State { 
  public int Id {get;set;}
  public string Name {get;set;}
}

//...sample code to add a new address using an existing State from DB (both as Nav prop and as FK id)