Search code examples
c#entity-frameworkef-code-firstentity-framework-6navigation-properties

is there a way to check All include navigation befor remove - Entity Framework


I have a User class that has 50 navigation properties(one to many). For example:

user>>post , user >> files , ...

In UserServiceLayer on Delete action , I want to check all user navigation Properties before deleting user and If at least one of them is greater than zero (0), there will be no permission to remove.

I have SoftDelete.

I don't want to use If blocks to Check All navigation .

Is there a way to check it ? or should I use If statement.


Solution

  • I would go with something like this:

    public class User
    {
        public int Id { get; set; }
        public bool IsDeleted { get; set; }
        public virtual ICollection<Post> Posts { get; set; }
        public virtual ICollection<File> Files { get; set; }
        // etc...
    
        public bool CanDelete()
        {
            return !Posts.Any() &&
                   !Files.Any(); // &&
                   // etc... 
        }
    }
    

    This will keep the logic for determining whether deletion is allowed with the entity, where you can more easily see the properties involved.

    You will still need to use an if statement in your UserServiceLayer, but it will be a very simple if statement.


    To make a generic version of this, one way to do it would be to use a custom attribute and an extension method that uses reflection to loop through all properties marked with the attribute.

    Define the attribute like this:

    [AttributeUsage(AttributeTargets.Property)]
    public class MustBeEmptyToDeleteAttribute : Attribute { }
    

    Add the attribute to properties on your entities, like this:

    public class User
    {
        public int Id { get; set; }
        public bool IsDeleted { get; set; }
    
        [MustBeEmptyToDelete] public virtual ICollection<Post> Posts { get; set; }
        [MustBeEmptyToDelete] public virtual ICollection<File> Files { get; set; }
        // etc...
    }
    

    Finally, create an extensions class for your entities:

    public static class EntityExtensions
    {
        public static bool CanDelete(this object entity)
        {
            return entity.GetType().GetProperties()
                .Where(x => x.IsDefined(typeof(MustBeEmptyToDeleteAttribute)))
                .Select(x => x.GetValue(entity))
                .OfType<IEnumerable<object>>()
                .All(x => !x.Any());
        }
    }