Reputation: 25955
I've been wasting two days now to try solve this problem but have yet to find a solution.
In my code that saves an entity with a relationship, I get this error when reaching ctx.SaveChanges()
:
Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values.
Shipment.cs
[ForeignKey("ShipmentNumber")]
public int? DefaultShipmentNumber { get; set; }
public virtual ShipmentNumber ShipmentNumber { get; set; }
ShipmentNumber.cs
[Column("shipment_id")]
[ForeignKey("Shipment")]
public byte ShipmentId { get; set; }
public virtual Shipment Shipment { get; set; }
To avoid circular references, ShipmentNumber belonging to Shipment is nullable (optional), whereas ShipmentNumber's dependency on Shipment is required.
I first create a Shipment, add it and then attach a ShipmentNumber to it and add it to table as well.
Here's the fluent API code:
modelBuilder.Entity<Shipment>()
.HasOptional<ShipmentNumber>((shipment) => shipment.ShipmentNumber)
.WithMany();
Shipment has one "true" ShipmentNumber, but many ShipmentNumbers can link to the same Shipment, hence the WithMany()
call (relation without a navigator property). In theory, both relations should always return one entity, but I know EF won't allow me a 1:1 relation here, so I'm using optional.
Here's the actual code:
shipment = tracker.Shipment;
ctx.Shipments.Add(shipment);
shipment.ShipmentNumber = new ShipmentNumber { Number = tracker.ShipmentNumber };
ctx.ShipmentNumbers.Add(shipment.ShipmentNumber);
ctx.SaveChanges();
If someone knows how to make it properly save the entity along with the relation, please do tell. I'm totally stuck at the moment.
Upvotes: 0
Views: 971
Reputation: 11990
Well, I don't know why you want a 1:n relationship in database and a 1:0.1 relationship in the model.
Case 1
If you want to make a 1:1 relationship, you should declare your model as follows:
public class Shipment
{
public int ShipmentId { get; set; }
//NO FK here
public virtual ShipmentNumber ShipmentNumber { get; set; }
}
public class ShipmentNumber
{
public int ShipmentId { get; set; } //ShipmentNumber PK is Also Shipment FK
public virtual Shipment Shipment { get; set; }
}
Mapping:
modelBuilder.Entity<Shipment>()
.HasKey(i => i.ShipmentId);
modelBuilder.Entity<ShipmentNumber>()
.HasKey(i => i.ShipmentId);
modelBuilder.Entity<Shipment>()
.HasRequired(i => i.ShipmentNumber)
.WithRequiredPrincipal(i => i.Shipment)
.WillCascadeOnDelete(false);
Generated Migration:
CreateTable(
"dbo.Shipments",
c => new
{
ShipmentId = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.ShipmentId);
CreateTable(
"dbo.ShipmentNumbers",
c => new
{
ShipmentId = c.Int(nullable: false),
})
.PrimaryKey(t => t.ShipmentId)
.ForeignKey("dbo.Shipments", t => t.ShipmentId)
.Index(t => t.ShipmentId);
Case 2
If you want to make a 1:n relationship:
public class Shipment
{
public int ShipmentId { get; set; }
public virtual ICollection<ShipmentNumber> ShipmentNumbers { get; set; }
}
public class ShipmentNumber
{
public int ShipmentNumberId { get; set; }
public int ShipmentId { get; set; }
public virtual Shipment Shipment { get; set; }
}
Mapping:
modelBuilder.Entity<Shipment>()
.HasKey(i => i.ShipmentId);
modelBuilder.Entity<ShipmentNumber>()
.HasKey(i => i.ShipmentNumberId);
modelBuilder.Entity<Shipment>()
.HasMany(i => i.ShipmentNumbers)
.WithRequired(i => i.Shipment)
.HasForeignKey(i => i.ShipmentId)
.WillCascadeOnDelete(false);
Generated Migration:
CreateTable(
"dbo.Shipments",
c => new
{
ShipmentId = c.Int(nullable: false, identity: true),
})
.PrimaryKey(t => t.ShipmentId);
CreateTable(
"dbo.ShipmentNumbers",
c => new
{
ShipmentNumberId = c.Int(nullable: false, identity: true),
ShipmentId = c.Int(nullable: false),
})
.PrimaryKey(t => t.ShipmentNumberId)
.ForeignKey("dbo.Shipments", t => t.ShipmentId)
.Index(t => t.ShipmentId);
Another problem is the code you are using to add items to database.
ctx.Shipments.Add(shipment);
shipment.ShipmentNumber = new ShipmentNumber { Number = tracker.ShipmentNumber };
//this line is not necessary
ctx.ShipmentNumbers.Add(shipment.ShipmentNumber);
ctx.SaveChanges();
When you add a new Shipment
all dependant objects will be inserted to database, if necessary.
Upvotes: 2