I need a way to delete a user and all it's constraints in other tables. I know of cascading delete in sql server but I can't use this for some reasons.
Let's say a user have several orders, each of that orders have some products. so I send the user in the method, it finds the orders, in a foreach loop it goes into that order and so on.
So I'm up to write a method to do this recursively; It must receive an object and find all its relations and goes through all of it.
I use EF power tools reverse engineer code first to generate these from database. here is my 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; }
}
using this method I am able to find all virtual ICollection
s in the user object.
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]
I see that it is Orders
, I must have something like this to be able to query:
var childType = ctx.Set<collectionType[0]>;
but I can't get the right casting and all.
and if this is completely wrong, any hints would be appreciated to get me to the right direction.
In case of someone need what I was looking for. This class gets an object and finds all relations with ICollection<T>
type and traverse through them recursively and deletes base childs.
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();
}
}
and use it like
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();
}