C# 检查附着的对象是否在导航属性上有任何相关数据库

C# 检查附着的对象是否在导航属性上有任何相关数据库,c#,.net,linq,reflection,entity-framework-6,C#,.net,Linq,Reflection,Entity Framework 6,我试图创建一个函数,可以检测一个附加对象是否在不同的表中有相关数据 我希望避免级联删除,但警告用户手动删除子项。 它必须是动态的,并且每个导航属性也是未知类型。 有太多不同的类实例,并且属性每天都在变化,所以我不能硬编码,否则我只能一个接一个地计算它们 我的问题是,当我选择值return by Property.GetValue()时,它是一个已装箱的对象,并且其中还有动态类型集合,因此我无法计算记录并进行相关检查 我的问题是如何将对象转换为引用Linq方法中的动态类型的ICollection

我试图创建一个函数,可以检测一个附加对象是否在不同的表中有相关数据

我希望避免级联删除,但警告用户手动删除子项。 它必须是动态的,并且每个导航属性也是未知类型。 有太多不同的类实例,并且属性每天都在变化,所以我不能硬编码,否则我只能一个接一个地计算它们

我的问题是,当我选择值return by Property.GetValue()时,它是一个已装箱的对象,并且其中还有动态类型集合,因此我无法计算记录并进行相关检查

我的问题是如何将对象转换为引用Linq方法中的动态类型的ICollection

我花了一整天的时间都没有得到答案,也许是我对EF概念的误解,但请帮忙,非常感谢

//Domain Model
public class Course
{
    [Key]
    public int CourseID { get; set; }
    [ForeignKey("CourseID")]
    public virtual ICollection<CourseTeacher> Teachers { get; set; }
    [ForeignKey("CourseID")]
    public virtual ICollection<CourseInfo> CourseInfo { get; set; }
    [ForeignKey("CourseID")]
    public virtual ICollection<CourseSession> Sessions { get; set; }
}

// Controller Delete Action
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
    Course course = db.Courses.Find(id);

    bool CannotDel = ValidateRelationalData(typeof(course), course);

    //if failed, warn the user and stop the delete action otherwise delete this record
}

// Public function I was trying to make 
public static bool ValidateRelationalData(Type anyType, dynamic anyInstance)
{
    bool IsExisted = anyType.GetProperties()
        .Where(p => typeof(IEnumerable).IsAssignableFrom(p.PropertyType) &&
            p.PropertyType != typeof(byte[]) &&
            p.PropertyType != typeof(string)
        )
        .Select(prop => (ICollection)prop.GetValue(anyInstance, null))
        .Where(c => c.Count() > 0)
        .Any(); //(ICollection)prop.GetValue(anyInstance, null)) won't work here, because no specific type
    return IsExisted;
}
//域模型
公共课
{
[关键]
public int CourseID{get;set;}
[外键(“CourseID”)]
公共虚拟ICollection教师{get;set;}
[外键(“CourseID”)]
公共虚拟ICollection CourseInfo{get;set;}
[外键(“CourseID”)]
公共虚拟ICollection会话{get;set;}
}
//控制器删除操作
[HttpPost,ActionName(“删除”)]
[ValidateAntiForgeryToken]
公共行动结果删除已确认(内部id)
{
Course=db.Courses.Find(id);
bool CannotDel=ValidateRelationalData(类型(课程),课程);
//如果失败,则警告用户并停止删除操作,否则删除此记录
}
//我想做的公众活动
公共静态bool ValidateRelationalData(类型anyType,动态anyInstance)
{
bool IsExisted=anyType.GetProperties()
.Where(p=>typeof(IEnumerable).IsAssignableFrom(p.PropertyType)&&
p、 PropertyType!=typeof(字节[])&&
p、 PropertyType!=类型(字符串)
)
.Select(prop=>(ICollection)prop.GetValue(anyInstance,null))
.Where(c=>c.Count()>0)
.Any();/(ICollection)prop.GetValue(anyInstance,null))在这里不起作用,因为没有特定的类型
回报是存在的;
}

我创建了一个基本方法来迭代实体DbSet的导航属性:

private static bool CheckIfAnyNavigationHasData<T>(T o, DbContext context) where T : class
{
    var objectContext = ((IObjectContextAdapter)context).ObjectContext;
    var elementType = objectContext.CreateObjectSet<T>().EntitySet.ElementType;
    var navigations = elementType.DeclaredNavigationProperties;

    var collectionNavigations = typeof(T).GetProperties().Where(w => w.PropertyType.Name.Equals(typeof(ICollection<>).Name)
                                                                || w.PropertyType.Name.Equals(typeof(HashSet<>).Name)
                                                                || w.PropertyType.Name.Equals(typeof(IList<>).Name))
                                                                .Join(navigations, t => t.Name, n => n.Name, (t, n) => t).ToArray();

    foreach (var property in collectionNavigations)
    {
        var p = o.GetType().GetProperty(property.Name);
        if (p == null)
            continue;

        var propertyValue = p.GetValue(o);
        if (propertyValue == null)
            continue;

        if ((int)property.PropertyType.GetMethod("get_Count").Invoke(propertyValue, null) > 0)
            return true;
    }

    return false;
}
因此,请使用:

using (var ctx = new Context())
{
    var course = ctx.Course.Find(2);
    var cannotDel = CheckIfAnyNavigationHasData(course, ctx);
}

非常先进和深入的EF理解,我真的学到了很多你的代码,你救了我一天(敬礼)。我考虑的一件事是有必要约束对象类型必须从类型参数派生?如果是,我们是否可以在签名中执行此类约束??或者我们应该在逻辑上验证它?经过测试并仍在学习,当有更多问题时会回来,感谢您的帮助!顺便说一句,你介意告诉我关于.GetMethod(“get_Count”)的事吗?既然我只知道您正在调用.Count(),那么如何计算字符串“get_Count”呢?但是这个模式是如何工作的呢?我想可能喜欢“accessor_FnName”?考虑得很好,我更新了帖子以更改方法签名。关于
.GetMethod(“get\u Count”)
我找到了使用
property.PropertyType.GetMethods()查找反射方法信息的方法。我不知道为什么有些方法有这种模式,这是一个好问题!敬礼
using (var ctx = new Context())
{
    var course = ctx.Course.Find(2);
    var cannotDel = CheckIfAnyNavigationHasData(course, ctx);
}