Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 实体框架包含在Where子查询中_C#_Entity Framework_Linq - Fatal编程技术网

C# 实体框架包含在Where子查询中

C# 实体框架包含在Where子查询中,c#,entity-framework,linq,C#,Entity Framework,Linq,我相信我在这里遗漏了一些明显的东西,我想不出来。我收到一个例外: LINQ to实体无法识别方法“System.LINQ.IQueryable1[Privilege]包括[Privilege,PrivilegeGetType]System.LINQ.IQueryable1[Privilege],System.LINQ.Expressions.Expression1[System.Func2[Privilege,PrivilegeGetType]]”方法,并且无法将此方法转换为存储表达式 运行此E

我相信我在这里遗漏了一些明显的东西,我想不出来。我收到一个例外:

LINQ to实体无法识别方法“System.LINQ.IQueryable1[Privilege]包括[Privilege,PrivilegeGetType]System.LINQ.IQueryable1[Privilege],System.LINQ.Expressions.Expression1[System.Func2[Privilege,PrivilegeGetType]]”方法,并且无法将此方法转换为存储表达式

运行此EF查询时:

return _context.Categories.Where(c =>
             _context.Privileges
               .Include(p => p.PrivilegeType)
              .Where(p => p.PrivilegeType.Code == "code").Any()).ToList();
我追求的最终结果是确定用户是否具有基于categoryId的特权。目前,为了简化陈述,我省略了Any条款中的条件

这种类型的查询可能吗

编辑: 以下是FulentApi配置:

public class PrivilegeConfiguration : EntityTypeConfiguration<Privilege>
{
    public PrivilegeConfiguration()
    {
        ToTable("ObjectPrivileges");

        HasKey(p => new { p.ObjectTypeId, p.ObjectId, p.PrivilegeTypeId });

        Property(p => p.ObjectTypeId)
            .HasColumnName("ObjectType")
            .HasMaxLength(2);

        Property(p => p.PrivilegeTypeId)
            .HasColumnName("PrivilegeID")
            .IsRequired();

        HasRequired(p => p.PrivilegeType);
    }
}

 public class PrivilegeTypeConfiguration : EntityTypeConfiguration<PrivilegeType>
{
    public PrivilegeTypeConfiguration()
    {
        ToTable("PrivilegeType");

        HasKey(p => p.PrivilegeTypeId);

        Property(p => p.PrivilegeTypeId)
            .HasColumnName("PrivilegeID");

        Property(p => p.ObjectTypeId)
            .HasColumnName("ObjectType")
            .HasMaxLength(2);

        Property(p => p.Code)
            .HasMaxLength(50);

        Property(p => p.Description)
            .HasMaxLength(255);
    }
}
下面是我想做的SQL表示:

SELECT * FROM Categories WHERE(
(NOT EXISTS 

    (
        SELECT P.ObjectType 
        FROM ObjectPrivileges P 
            INNER JOIN PrivilegeType PT ON P.PrivilegeID = PT.PrivilegeID 
        WHERE 
            (
                P.PrivilegeValue > 0 
                AND PT.Code ='code' 
                AND P.ObjectType = 'SELECT'  
                AND P.ObjectID = 1 -- CategoryId
            )
    )
) OR

EXISTS 
    (
        SELECT P.ObjectType 
        FROM ObjectPrivileges P 
            INNER JOIN PrivilegeType PT ON P.PrivilegeID = PT.PrivilegeID 
        WHERE 
            (
                P.PrivilegeValue > 0 
                AND PT.Code = 'code' 
                AND P.ObjectType = 'SELECT' 
                AND P.ObjectID = 1 -- CategoryId
                AND (P.UserID = 57 OR P.GroupID IN (SELECT GroupID FROM Group_User WHERE UserID = 57))
            )
    ))

您当前的查询实际上没有执行与不同实体相关的任何类型的筛选:

return _context.Categories.Where(c =>
               _context.Privileges
               .Include(p => p.PrivilegeType)
               Where(p => p.PrivilegeType.Code == "code").Any()).ToList();
如果数据库中存在PrivilegeType.code值为code的特权实体,则此代码将转到数据库并获取数据库中的所有类别。它不过滤任何内容,只返回所有类别

正如@dcg在评论中提到的,您在第一个lambda表达式中没有使用c变量,我确信这是您作为c对象接收到的实际异常的原因,在这种情况下,上下文不能传递到像这样的where表达式中

决议如下:

_context.Categories.Where(c => c.Privileges.Any(p => p.PrivilegeType.Code == "code")).ToList();
这假定类别和权限之间存在外键关系。如果不这样做,则需要重新构造这两个表的关联方式,或者提供有关您试图使用什么连接这两个实体的更多详细信息

编辑:

在您的帖子中澄清“是”之后,上面的查询就是您要查找的,但是您需要实际映射类别和特权实体之间的关系。在类别实体映射配置上执行以下操作:

public class Category
{
    public int CategoryId { get; set; }
    public int PrivilegeId { get; set; }

    public virtual ICollection<Privilege> Privilege { get; set; }
}

public class Privilege
{
    public int PrivilegeId { get; set; }
    public int ObjectId { get; set; }
}

public class CategoryMap : EntityTypeConfiguration<Category>
{
    public CategoryMap()
    {
        ToTable("Categories");
        HasKey(x => x.CategoryId);

        HasMany(x => x.Privilege)
            .WithMany()
            .Map(x =>
            {
                x.MapLeftKey(nameof(Category.PrivilegeId));
                x.MapRightKey(nameof(Privilege.ObjectId));
            });
    }
}

public class PrivilegeMap : EntityTypeConfiguration<Privilege>
{
    public PrivilegeMap()
    {
        ToTable("Categories");
        HasKey(x => x.PrivilegeId);
    }
}
这将允许您在类别和权限之间定义一个1-*的关系,而不需要该权限实际上具有任何类型的返回类别的关系。因此,您将能够编写类似这样的复杂查询

编辑:

我曾尝试重新创建您的SQL查询,尽管我必须根据上述代码的结构构建自己的本地上下文,但它可能并不准确

我相信这将生成与您的查询相同的结果集。它可能不会生成相同的SQL,但结果应该是相同的

public IQueryable<Category> Query(int userId)
{
    var db = new Context();

    var groupUsers = db.GroupUsers.Where(x => x.UserId == userId).Select(gu => gu.GroupId);

    var first = db.Privileges
        .Join(db.PrivilegeTypes, p => p.PrivilegeTypeId, pt => pt.PrivilegeTypeId, (p, pt) => new { P = p, PT = pt })
        .Where(join => join.P.PrivilegeValue > 0 &&
                        join.PT.Code == "code" &&
                        join.P.ObjectTypeId == "SELECT" &&
                        join.P.ObjectTypeId == "1");

    var second = first.Where(join => join.P.UserId == userId || groupUsers.Contains(join.P.UserId));

    return db.Categories.Where(c => first.All(join => join.P.ObjectId != c.CategoryId) ||
                                    second.Any(join => join.P.ObjectId == c.CategoryId));
}

Query(57); // Look up UserID 57
问题是:

正如评论中所说,类别和特权之间没有外键关系。存在一种软关系:Privilege.ObjectID指向表的主键。问题是您的子查询没有关联类别和特权,因为没有使用CategoryID。对于任何类别,条件要么为真,要么为假

“包含”仅在填充查询结果中实体的导航属性时有效。换句话说,Privileges.Includep=>p.privilegegetype仅在返回特权时有效。除此之外,不能过滤包含项,因此它们不能用作过滤条件

所以首先要做的是:匹配CategoryID。任何这种性质的查询都应该像

_context.Categories
        .Where(c => !_context.Privileges
                             .Any(p => p.ObjectId == c.CategoryId
                                    && ...))
第二种方法是以允许对其进行筛选的方式使用PrivilegeType:p.PrivilegeType.Code==Code

应用这些修复程序,整个查询将如下所示:

var userId = 57;
return _context.Categories
   .Where(c => 
       !_context.Privileges
                .Any(p => p.ObjectId == c.CategoryId
                       && p.PrivilegeValue > 0
                       && p.PrivilegeType.Code == "code"
                       && p.ObjectType = 'SELECT')
     || _context.Privileges
                .Any(p => p.ObjectId == c.CategoryId
                       && p.PrivilegeValue > 0
                       && p.PrivilegeType.Code == "code"
                       && p.ObjectType = 'SELECT'
                       && (p.UserId == userId
                             || _context.GroupUsers
                                        .Any(gu => gu.UserId == userId
                                                && gu.GroupID == p.GroupID)))
         );

您是否映射了外键关系?你能给我们看看你的实体代码和映射代码吗?你不应该在lambda中的任何地方使用c吗?@RobertPetz我在编辑中添加了映射代码。你为什么在where表达式中使用_context.Privileges?你不能这样做,你想做什么?也许可以试着找一个关于查询相关实体的教程?是的,那么根据实体框架,两者之间没有关系?然后,您必须在Where.Tanks中手动加入这两个,以便快速回复!我更详细地更新了我上面的问题。@INVARZIM我更新了我的答案-我没有直接针对数据库运行此操作,因此如果有任何运行时错误,请告诉我,但它应该为您指出正确的方向来执行您试图执行的操作。嗯,我理解FulentApi创建两个实体之间的虚拟关系,谢谢你教我怎么做;然而,如何将上面的SQL查询转换成我所需要的,我正在努力。你有什么建议吗?@investrzim我更新了我的答案,我相信这将重新创建你的查询-如果没有,至少应该给你一个合适的跳转开始。请注意,我没有使用我最初的回答中提到的关系——这是因为你的问题本质上很奇怪,它实际上不适合这种关系。非常感谢你花时间和精力帮助我。如果
联接中的objectId不是静态的,但我需要category表中的category Id。格茨阿诺德提出了一个对我有用的问题:太棒了,这就像一个魅力!我不知道includes不能用在where子句中。我仍然在思考EF,谢谢你的详细回答。随机附带问题,你知道有什么好方法可以将这个where条件重新用于其他实体,不仅仅是类别,还有表a,B,您必须在泛型方法中构建表达式,该方法使用泛型类型参数来构建lambda表达式的参数部分。如果你需要更具体的帮助,你最好问一个新问题。
var userId = 57;
return _context.Categories
   .Where(c => 
       !_context.Privileges
                .Any(p => p.ObjectId == c.CategoryId
                       && p.PrivilegeValue > 0
                       && p.PrivilegeType.Code == "code"
                       && p.ObjectType = 'SELECT')
     || _context.Privileges
                .Any(p => p.ObjectId == c.CategoryId
                       && p.PrivilegeValue > 0
                       && p.PrivilegeType.Code == "code"
                       && p.ObjectType = 'SELECT'
                       && (p.UserId == userId
                             || _context.GroupUsers
                                        .Any(gu => gu.UserId == userId
                                                && gu.GroupID == p.GroupID)))
         );