Reputation: 926
I have 3 entities set up in the follow way.
public class Person
{
[Key]
public int PersonId { get; set; }
public virtual ICollection<Location> Locations { get; set; }
}
public class Location
{
[Key]
public int LocationId { get; set; }
public int PersonId { get; set; }
public virtual Person Person { get; set; }
public virtual ICollection<Value> Values{get; set; }
}
public class Value
{
[Key]
public int ValueId { get; set; }
public int LocationId { get; set; }
public virtual Location Location { get; set; }
}
Using fluent Api, I have setup the foreign key configuration from Location to Person and also from Value to Location.
// Person to Location(s)
modelBuilder.Entity<Person>()
.HasMany(e => e.Locations)
.WithRequired(e => e.Person)
.WillCascadeOnDelete(true);
// Location to Value(s)
modelBuilder.Entity<Location>()
.HasMany(e => e.Values)
.WithRequired(e => e.Location)
.WillCascadeOnDelete(false);
What I'm trying to do is create a new Person, add a Location and to that location add a value.
So naturally I'll first create a person
[pseudo code]
var newPerson = new Person();
then create the Location
[pseudo code]
var newLocation = new Location { Person = newPerson };
and then finally the value
[pseudo code]
var newValue = new Value { Location = newLocation };
DbContext.Values.Add(newValue); DbContext.SaveChanges();
What's happening is that I'm able to successfully save the Location with the newly created person if I want but when I try to get another level down and add the value like above it's complaining about the foreign key constraint between Value and Location.
I have managed to get it to work by first adding the Location to the context and doing a save changes but this would mean that my code isn't transaction safe.
Upvotes: 3
Views: 829
Reputation: 30454
You have modeled a proper one-to-many relation ship between Persons
and Locations
: a Person
has zero or more Locations
, and every Location
belongs to exactly one Person. If the Person
seizes to exist, then his Locations
also seize to exist.
However, you have modeled the relation between Locations
and Values
differently. Apparently if a Location
seizes to exist, the Values
don't have to be deleted because of the WillCasscaseOnDelete(false)
. What would the value of LocationId
mean if the Location
is deleted?
You solution depends on what you intended to model:
WillCascadeOnDelete(true)
. Upvotes: 1
Reputation: 654
You're able to save the person because it does not include a foreign key, meaning it does not have a property for Locationid but in the case of values, it requires Locationid, that is the entire purpose of defining a relation.
When you define a relation between two tables, you simply can not avoid saving records in one of the table without the foreign key of the other table. Add the location, save the changes, in the next line, add your value and then save changes. This procedure does not make your application vulnerable in any way.
If you still don't want to do this, then instead of defining the relation with Entity Framework, make the Locationid unique in your values table and perform custom validations yourself but I wouldn't suggest that.
Upvotes: 1