The DELETE statement conflicted with the SAME TABLE REFERENCE constraint with Entity Framework

前端 未结 3 1136
梦如初夏
梦如初夏 2021-01-01 18:15

I have a table with a self reference where the ParentId is an FK to the ID (PK).
Using EF (code-first), I\'ve set up my relationship as follows:

this.Ha         


        
3条回答
  •  梦毁少年i
    2021-01-01 18:59

    I realize the answer is a year old, but I find it incomplete. In my mind, a self-referencing table is used to represent an arbitrary depth.

    For example, consider the following structure:

    /*  
     *  earth
     *      europe
     *          germany
     *          ireland
     *              belfast
     *              dublin
     *      south america
     *          brazil
     *              rio de janeiro
     *          chile
     *          argentina                 
     *               
     */
    

    The answer does not solve how to delete earth, or europe, from the structure above.

    I submit the following code as an alternative (modification of answer provided by Slauma, who did a good job btw).

    In the MyContext class, add the following methods:

    public void DeleteMyEntity(MyEntity entity)
    {
        var target = MyEntities
            .Include(x => x.Children)
            .FirstOrDefault(x => x.Id == entity.Id);
    
        RecursiveDelete(target);
    
        SaveChanges();
    
    }
    
    private void RecursiveDelete(MyEntity parent)
    {
        if (parent.Children != null)
        {
            var children = MyEntities
                .Include(x => x.Children)
                .Where(x => x.ParentId == parent.Id);
    
            foreach (var child in children)
            {
                RecursiveDelete(child);
            }
        }
    
        MyEntities.Remove(parent);
    }
    

    I populate the data using code-first with the following class:

    public class TestObjectGraph
    {
        public MyEntity RootEntity()
        {
            var root = new MyEntity
            {
                Name = "Earth",
                Children =
                    new List
                        {
                            new MyEntity
                            {
                                Name = "Europe",
                                Children =
                                    new List
                                    {
                                        new MyEntity {Name = "Germany"},
                                        new MyEntity
                                        {
                                            Name = "Ireland",
                                            Children =
                                                new List
                                                {
                                                    new MyEntity {Name = "Dublin"},
                                                    new MyEntity {Name = "Belfast"}
                                                }
                                        }
                                    }
                            },
                            new MyEntity
                            {
                                Name = "South America",
                                Children =
                                    new List
                                    {
                                        new MyEntity
                                        {
                                            Name = "Brazil",
                                            Children = new List
                                            {
                                                new MyEntity {Name = "Rio de Janeiro"}
                                            }
                                        },
                                        new MyEntity {Name = "Chile"},
                                        new MyEntity {Name = "Argentina"}
                                    }
                            }
                        }
            };
    
            return root;
        }
    }
    

    which I save to my database with the following code:

    ctx.MyEntities.Add(new TestObjectGraph().RootEntity());
    

    then invoke the deletes like so:

    using (var ctx = new MyContext())
    {
        var parent = ctx.MyEntities
            .Include(e => e.Children)
            .FirstOrDefault();
    
        var deleteme = parent.Children.First();
    
        ctx.DeleteMyEntity(deleteme);
    }
    

    which results in my database now having a structure like so:

     /*  
     *  earth
     *      south america
     *          brazil
     *              rio de janeiro
     *          chile
     *          argentina                 
     *               
     */
    

    where europe and all of its children are deleted.

    in the above, I am specifying the first child of the root node, to demonstrate that using my code you can recursively delete a node and all of its children from anywhere in the hierarchy.

    if you want to test deleting everyting, you can simply modify the line like this:

    ctx.DeleteMyEntity(parent);
    

    or whichever node you want in the tree.

    obviously, I won't get the bounty, but hopefully my post will help someone looking for a solution that works for self-referencing entities of arbitrary depth.

    Here is the full source, which is a modified version of Slauma's code from the selected answer:

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    
    namespace EFSelfReference
    {
        public class MyEntity
        {
            public int Id { get; set; }
            public string Name { get; set; }
    
            public int? ParentId { get; set; }
            public MyEntity Parent { get; set; }
    
            public ICollection Children { get; set; }
        }
    
        public class MyContext : DbContext
        {
            public DbSet MyEntities { get; set; }
    
            protected override void OnModelCreating(DbModelBuilder modelBuilder)
            {
                modelBuilder.Entity()
                    .HasOptional(e => e.Parent)
                    .WithMany(e => e.Children)
                    .HasForeignKey(e => e.ParentId);
            }
    
    
            public void DeleteMyEntity(MyEntity entity)
            {
                var target = MyEntities
                    .Include(x => x.Children)
                    .FirstOrDefault(x => x.Id == entity.Id);
    
                RecursiveDelete(target);
    
                SaveChanges();
    
            }
    
            private void RecursiveDelete(MyEntity parent)
            {
                if (parent.Children != null)
                {
                    var children = MyEntities
                        .Include(x => x.Children)
                        .Where(x => x.ParentId == parent.Id);
    
                    foreach (var child in children)
                    {
                        RecursiveDelete(child);
                    }
                }
    
                MyEntities.Remove(parent);
            }
        }
    
        public class TestObjectGraph
        {
            public MyEntity RootEntity()
            {
                var root = new MyEntity
                {
                    Name = "Earth",
                    Children =
                        new List
                        {
                            new MyEntity
                            {
                                Name = "Europe",
                                Children =
                                    new List
                                    {
                                        new MyEntity {Name = "Germany"},
                                        new MyEntity
                                        {
                                            Name = "Ireland",
                                            Children =
                                                new List
                                                {
                                                    new MyEntity {Name = "Dublin"},
                                                    new MyEntity {Name = "Belfast"}
                                                }
                                        }
                                    }
                            },
                            new MyEntity
                            {
                                Name = "South America",
                                Children =
                                    new List
                                    {
                                        new MyEntity
                                        {
                                            Name = "Brazil",
                                            Children = new List
                                            {
                                                new MyEntity {Name = "Rio de Janeiro"}
                                            }
                                        },
                                        new MyEntity {Name = "Chile"},
                                        new MyEntity {Name = "Argentina"}
                                    }
                            }
                        }
                };
    
                return root;
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Database.SetInitializer(
                   new DropCreateDatabaseAlways());
                using (var ctx = new MyContext())
                {
                    ctx.Database.Initialize(false);
    
                    ctx.MyEntities.Add(new TestObjectGraph().RootEntity());
                    ctx.SaveChanges();
                }
    
                using (var ctx = new MyContext())
                {
                    var parent = ctx.MyEntities
                        .Include(e => e.Children)
                        .FirstOrDefault();
    
                    var deleteme = parent.Children.First();
    
                    ctx.DeleteMyEntity(deleteme);
                }
    
                Console.WriteLine("Completed....");
                Console.WriteLine("Press any key to exit");
                Console.ReadKey();
            }
        }
    }
    

提交回复
热议问题