使用递归方法级联删除
cascading delete using recursive method
我需要一种方法来删除用户及其在其他表中的所有约束。我知道 sql 服务器中的级联删除,但由于某些原因我不能使用它。
假设一个用户有多个订单,每个订单都有一些产品。所以我在方法中发送用户,它找到订单,在 foreach 循环中它进入该订单等等。
所以我要写一个方法来递归地做这个;它必须接收一个对象并找到它的所有关系并遍历所有对象。
我首先使用 EF power tools 逆向工程代码从数据库生成这些代码。这是我的 class:
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
。
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?
}
}
}
using collectionType[0]
我看到是Orders
,我必须有这样的东西才能查询:
var childType = ctx.Set<collectionType[0]>;
但我找不到合适的角色。
如果这是完全错误的,任何提示都会让我找到正确的方向。
这完全不合适。当您应该首先使用这些用户映射的关系模型时,您正在粗略地执行数据库关系操作。
您的应用程序最好用作调用存储过程,其中数据库语言可以映射所涉及的表并为用户及其对象删除正确的行。
与您的 dba 和设计这些表的开发人员一起工作,将数据库操作留给数据库,将框架操作留给框架。
@clifton_h的回答我觉得很对。但是如果你想使用 youre 方法,你可以使用它来 return 要包含的字符串。用于查找和删除对象。
var user = users.Include("Orders.OrdersProducts");
ctx.Delete(user);
ctx.SaveChanges();
注意错别字。我把答案写在我的phone.
如果有人需要我正在寻找的东西。 class 获取一个对象并找到所有具有 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();
}
我需要一种方法来删除用户及其在其他表中的所有约束。我知道 sql 服务器中的级联删除,但由于某些原因我不能使用它。
假设一个用户有多个订单,每个订单都有一些产品。所以我在方法中发送用户,它找到订单,在 foreach 循环中它进入该订单等等。
所以我要写一个方法来递归地做这个;它必须接收一个对象并找到它的所有关系并遍历所有对象。
我首先使用 EF power tools 逆向工程代码从数据库生成这些代码。这是我的 class:
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
。
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?
}
}
}
using collectionType[0]
我看到是Orders
,我必须有这样的东西才能查询:
var childType = ctx.Set<collectionType[0]>;
但我找不到合适的角色。
如果这是完全错误的,任何提示都会让我找到正确的方向。
这完全不合适。当您应该首先使用这些用户映射的关系模型时,您正在粗略地执行数据库关系操作。
您的应用程序最好用作调用存储过程,其中数据库语言可以映射所涉及的表并为用户及其对象删除正确的行。
与您的 dba 和设计这些表的开发人员一起工作,将数据库操作留给数据库,将框架操作留给框架。
@clifton_h的回答我觉得很对。但是如果你想使用 youre 方法,你可以使用它来 return 要包含的字符串。用于查找和删除对象。
var user = users.Include("Orders.OrdersProducts");
ctx.Delete(user);
ctx.SaveChanges();
注意错别字。我把答案写在我的phone.
如果有人需要我正在寻找的东西。 class 获取一个对象并找到所有具有 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();
}