2017-08-05 126 views
-1

我需要一种方法来删除用户及其所有在其他表中的约束。我知道在sql server中级联删除,但由于某些原因,我无法使用它。使用递归方法级联删除

比方说,一个用户有几个订单,每个订单都有一些产品。所以我在方法中发送用户,发现订单,在foreach循环中进入该订单等等。

所以我要写一个方法来递归地做到这一点;它必须接收一个对象,并找到它的所有关系,并通过它所有的关系。

我首先使用EF电动工具反向工程代码从数据库生成这些代码。这里是我的课:

public partial class myDbContext: DbContext 
{ 
    ... 

    public DbSet<Users> Users{ get; set; } 
    public DbSet<Orders> Orders{ get; set; } 
    public DbSet<Products> Products{ get; set; } 
    public DbSet<OrderProducts> OrderProducts{ get; set; } 

    ... 
} 
public partial class Users 
{ 
    public int UserID { get; set; } 
    public string Username { get; set; } 
    public virtual ICollection<Orders> Orders{ get; set; } 
} 
public partial class Orders 
{ 
    public int OrderID { get; set; } 
    public virtual Users users { get; set; } 
    public virtual ICollection<OrderProducts> OPs { get; set; } 
} 
public partial class OrderProducts 
{ 
    public int OPID { get; set; } 
    public virtual Orders orders { get; set; } 
    public virtual Product products { get; set; } 
} 

使用这种方法,我能找到的所有virtual ICollection S IN的用户对象。

private void DeleteObjectAndChildren(object parent) 
    { 
     using (var ctx = new myDbContext()) 
     { 
      Type t = parent.GetType(); 

      //these are all virtual properties of parent 
      var properties = parent.GetType().GetProperties().Where(p => p.GetGetMethod().IsVirtual); 
      foreach (var p in properties) 
      { 
       var collectionType = p.PropertyType.GetGenericArguments(); 
       //collectionType[0] gives me the T type in ICollection<T> 

       //what to do next? 
      } 
     } 
    } 

使用collectionType[0]我看到它是Orders,我必须有这样的事情能够查询:

var childType = ctx.Set<collectionType[0]>; 

,但我不能得到正确的铸造和所有。

如果这是完全错误的,任何提示将不胜感激让我走向正确的方向。

回答

0

如果有人需要我正在寻找的东西。这个类获取一个对象,并找到与ICollection<T>类型的所有关系,并递归遍历它们并删除基础子对象。

public class RemoveEntityAndAllRelations 
{ 
    private DbContext _context; 

    public void SetContext(DbContext ctx) 
    { 
     _context = ctx; 
    } 

    public void RemoveChildren(object parent) 
    { 
     Type obj = parent.GetType(); 

     MethodInfo method = typeof(RemoveUserAndAllRelations).GetMethod("GetICollections"); 
     MethodInfo generic = method.MakeGenericMethod(obj); 

     var properties = (PropertyInfo[])generic.Invoke(this, null); 
     if (properties.Any()) 
     { 
      foreach (PropertyInfo propertyInfo in properties) 
      { 
       object child = propertyInfo.GetValue(parent, null); 
       RemoveChildren(child); 
      } 

      try 
      { 
       dynamic dd = parent; 
       _context.Entry(dd[0]).State = EntityState.Deleted; 
       _context.SaveChanges(); 
      } 
      catch (Exception) 
      { 
        //do what you like 
      } 
     } 
     else 
     { 
      try 
      { 
       dynamic dd = parent; 
       _context.Entry(dd[0]).State = EntityState.Deleted; 
       _context.SaveChanges(); 
      } 
      catch (Exception) 
      { 
        //do what you like 
      } 
     } 
    } 
    public PropertyInfo[] GetICollections<TEntity>() where TEntity : class 
    { 
     return typeof(TEntity).GetProperties().Where(m => 
      m.PropertyType.IsGenericType && 
      m.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>) 
     ).ToArray(); 
    } 
} 

,并使用它像

using (var ctx = new myDbContext()) 
{ 
    var user = ctx.Users.FirstOrDefault(x => x.UserID == userId); 
    RemoveEntityAndAllRelations controller = new RemoveUserAndAllRelations(); 

    controller.SetContext(ctx); 
    controller.RemoveChildren(user); 

    ctx.Core_Users.Remove(user); 
    ctx.SaveChanges(); 
} 
0

这完全不合适。当您应该首先使用映射这些用户的关系模型时,您正在诅咒地执行数据库关系操作。

您的应用程序最适合调用存储过程,其中数据库语言可以映射涉及的表并为用户及其对象删除正确的行。

与您的dba以及那些设计这些表并将数据库操作保留到框架的数据库和框架操作的开发人员一起工作。

+0

它只是一个局部的测试应用程序,我需要删除所有测试用户,事情随之而来。这并不意味着要在日常使用情况下发布和使用。此外,还有很多关系和表格,我无法想象在数据库方面做到这一点。 –

0

@clifton_h的回答对我来说感觉很对。但是如果你想使用你的方法,你可以用它来返回一个字符串来包含。用于查找和删除对象。

var user = users.Include("Orders.OrdersProducts"); 
ctx.Delete(user); 
ctx.SaveChanges(); 

小心输入错字。我在手机上写下了答案。