I am using EF and Code First.
I have a Transaction class like this:
[Table("Transacties")]
public class Transactie
{
[Key]
[Column(Order = 1)]
[StringLength(128)]
public string KIMTransactieCode { get; set; }
[Column(Order = 2)]
[StringLength(128)]
public string BovenliggendeKIMTransactieCode { get; set; }
[ForeignKey("BovenliggendeKIMTransactieCode")]
public Transactie BovenLiggendeTransactie { get; set; }
public DateTime? DatumLaatstBekeken { get; set; }
public bool? IsZichtbaar { get; set; }
public DateTime? IsZichtbaarGewijzigdOp { get; set; }
public OpnameInfo OpnameInfo { get; set; }
}
The relation is as follows:
A transaction can have a subtransaction, when there is subtransaction a reference is required to the parent transaction ('BovenliggendeKIMTransactieCode'). This is complete defined in one class/table.
It uses mainly data annotations.
I want to have a cascade delete on this class: when the (parent) transaction is deleted, all the related subtransactions must be deleted also.
I tried to invoke cascade delete as follows:
var transactions = mailboxDataContext.Transacties
.Where(tr => tr.BovenliggendeKIMTransactieCode == null &&
tr.IsZichtbaar.HasValue &&
!tr.IsZichtbaar.Value &&
tr.IsZichtbaarGewijzigdOp.HasValue &&
tr.IsZichtbaarGewijzigdOp.Value < selectionDateTime)
.ToList(); // Materialize
if (transactions.Count > 0)
{
foreach (var transaction in transactions)
{
mailboxDataContext.SetDeleted(transaction);
}
mailboxDataContext.SaveChanges();
}
but then I get:
"The DELETE statement conflicted with the SAME TABLE REFERENCE
constraint
\"FK_dbo.Transacties_dbo.Transacties_BovenliggendeKIMTransactieCode\".
The conflict occurred in database \"PROGISKIM_Mailbox\", table
\"dbo.Transacties\", column 'BovenliggendeKIMTransactieCode'.\r\nThe
statement has been terminated."
How can this be fixed ?
Update:
When I try to delete the main row in SSMS I get this exception also...
Related
I've searched and nothing I've come across works for this problem. I have child entities that all have a date completed field. When the parent entity is updated, I want to delete any child entities that don't have a value for the date completed field. Here's the code.
public int Save(ImmunizationForm form)
{
_context.Entry(form).State = EntityState.Detached;
//only clear our incomplete immunizations
var incompleteImmunizations = _context.ImmunizationFormImmunization.Where(x =>
x.ImmunizationFormId == form.Id && !x.DateCompleted.HasValue);
if (incompleteImmunizations.Any())
{
foreach (var i in incompleteImmunizations){
//_context.Entry(i).State = EntityState.Deleted;
_context.ImmunizationFormImmunization.Remove(i);
}
_context.SaveChanges(); //errors here
}
.....
}
My suspicion was that because I'm passing in an ImmunizationForm entity that has an Id value (meaning I'm not adding a new parent but updating), I would need to set the State to EntityState.Detached because further in my code I actually grab the entity to update from the database. But, that doesn't seem to help. As you can see I've tried both setting the State of the incompleteImmunization object to delete or just try to remove it. Neither are working. I keep getting the same error message...
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
Parent class
public class ImmunizationForm
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ImmunizationForm()
{
ImmunizationFormImmunizations = new HashSet<ImmunizationFormImmunization>();
}
public int Id { get; set; }
public string Name { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ImmunizationFormImmunization> ImmunizationFormImmunizations { get; set; }
}
Child class
public class ImmunizationFormImmunization
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public ImmunizationFormImmunization()
{
}
public int Id { get; set; }
[ForeignKey("ImmunizationForm")]
public int ImmunizationFormId { get; set; }
public short ImmunizationTypeId { get; set; }
public byte? GroupId { get; set; }
public byte DocumentationRequirement { get; set; }
public DateTime? DateCompleted { get; set; }
public string RejectionReason { get; set; }
public DateTime? RejectedDate { get; set; }
[Column(TypeName = "numeric")]
public decimal? RejectedBy { get; set; }
public virtual ImmunizationForm ImmunizationForm { get; set; }
public virtual TypeImmunization TypeImmunization { get; set; }
}
When deleting a UserGroup the following exception is thrown.
SqlException: The DELETE statement conflicted with the REFERENCE
constraint "FK_SecurityAssignments_UserGroups_UserGroupId". The
conflict occurred in database "AppDb", table
"dbo.SecurityAssignments", column 'UserGroupId'. The statement has
been terminated.
I've followed the approach from this post, but apparantly missed something ;-)
Cascade deleting with EF Core
The models :
public class UserGroup
{
public int Id { get; set; }
public virtual ICollection<SecurityAssignment> SecurityAssignments { get; set; } = new List<SecurityAssignment>();
}
public class Role
{
public int Id { get; set; }
public virtual ICollection<SecurityAssignment> SecurityAssignments { get; set; } = new List<SecurityAssignment>();
}
public class SecurityAssignment
{
public int Id { get; set; }
public int UserGroupId { get; set; }
public virtual UserGroup UserGroup { get; set; }
public int RoleId { get; set; }
public virtual Role Role { get; set; }
}
Customisation in OnModelCreating
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
//Remove cascade delete unless explicit set below
var cascadeFKs = builder.Model
.GetEntityTypes()
.SelectMany(t => t.GetForeignKeys())
.Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade);
foreach (var fk in cascadeFKs)
{
fk.DeleteBehavior = DeleteBehavior.Restrict;
}
// explicit set cascade delete
// Remove security assignments when group deleted
builder.Entity<UserGroup>().HasMany(x => x.SecurityAssignments).WithOne(x => x.UserGroup).HasForeignKey(x => x.UserGroupId).OnDelete(DeleteBehavior.Cascade);
}
Any suggestions ?
The above code and configuration is correct. The problem was that I added the cascade-delete changes but did NOT created a migration.
!!! When changing the model by updating the OnModelCreated, DO NOT FORGET to create a migration !!!
I have a Submission controller that has one to many relationship to few other tables. Below is my model:
public partial class Submission
{
public Submission()
{
this.WorkorderLogs = new HashSet<WorkorderLog>();
}
public int Id { get; set; }
public int WorkOrderId { get; set; }
public int PartStagingId { get; set; }
public System.DateTime SubmissionDate { get; set; }
public virtual PartStaging PartStaging { get; set; }
public virtual WorkOrder WorkOrder { get; set; }
public virtual ICollection<WorkorderLog> WorkorderLogs { get; set; }
}
I want the application to delete all child records when I delete a Submission record. Below is my delete method:
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Submission submission = db.Submissions.Find(id);
foreach (var w in submission.WorkorderLogs)
{
submission.WorkorderLogs.Remove(w);
}
db.Submissions.Remove(submission);
db.SaveChanges();
return RedirectToAction("Index");
}
This gives me an error after the first iteration of the foreach loop. Below is the error I get:
Exception Details: System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
How do I delete the child records in this case?
I do not enable the On Delete Cascade, but I modified the foreach loop and it works
foreach (var w in db.WorkorderLogs.Where(x => x.SubmissionId == submission.Id))
{
db.WorkorderLogs.Remove(w);
}
I try to add new model to DB but the model have child that already exists
and i got this error:
"A referential integrity constraint violation occurred: The property value(s) of 'Category.ID' on one end of a relationship do not match the property value(s) of 'Lesson.CategoryID' on the other end."
for example:
public class Category
{
public int ID { get; set; }
public string Name{ get; set; }
public List<Lesson> Lessons{ get; set; }
}
public class Lesson
{
public int ID { get; set; }
public string Name{ get; set; }
public List<Category> Categories { get; set; }
}
I think that the Category ID still 0 until the DB will generate new ID and Lesson.CategoryID filled in 0 that not exist in Categories
Save code:
DB.Categories.Add(obj);
DB.ChangeTracker.Entries()
.Where(x => x.Entity is BaseModel && x.State == EntityState.Added && ((BaseModel)x.Entity).ID > 0)
.ToList().ForEach(x => x.State = EntityState.Unchanged);
Any idea how to fix that?
Thanks anyway
I get this error:
System.Data.SqlClient.SqlException The DELETE statement conflicted
with the REFERENCE constraint "FK_comments_postId__164452B1". The
conflict occurred in database "awe", table "dbo.comments", column
'postId'. The statement has been terminated.
I have this structure:
public class Post
{
public long Id { get; set; }
public string Body { get; set; }
public long? ParentId { get; set; }
public virtual Post Parent { get; set; }
public virtual ICollection<Post> Posts { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public long Id { get; set; }
public long PostId { get; set; }
public virtual Post Post { get; set; }
public string Body { get; set; }
}
my delete method:
public void Delete(long id)
{
var p = context.Set<Post>().Get(id);
if(p == null) throw new MyEx("this post doesn't exist");
if (p.Posts.Count > 0) throw new MyEx("this post has children and it cannot be deleted");
context.Set<Post>().Remove(p);
context.SaveChanges();
}
my DbContext:
public class Db : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
}
It sounds like the Post that you are trying to delete has child Comments.
Entity Framework will not take responsibility for cascading a delete in the database – it expects that you will achieve this by setting a cascading delete on the foreign key relationship in the RDBMS.
Having said this, if you delete a parent entity in Entity Framework, it will attempt to issue delete statements for any child entities which have been loaded into the current DbContext, but it will not initialize any child entities which have not yet been loaded. This may lead to the RDBMS throwing foreign key constraint violation exceptions if a cascading delete has not been specified, like the one you are seeing. For more details about how cascade delete “works” in Entity Framework, see this blog post.