我相信我错过了一些明显的东西,我无法理解。我接受了例外:
LINQ to Entities无法识别方法'System.Linq.IQueryable
1[Privilege] Include[Privilege,PrivilegeType](System.Linq.IQueryable
1 [Privilege],System.Linq.Expressions.Expression1[System.Func
2 [Privilege,PrivilegeType]])'方法,并且此方法无法转换为商店表达式。
当我运行此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);
}
}
编辑2:
where条件是我想放入查询以限制将返回的记录数量的东西。我正在更新遗留数据库,并尝试匹配他们现有的数据库以保持尽可能接近。
以下是我正在尝试的完整查询:
var query = _context.Categories.AsQueryable();
if (!string.IsNullOrEmpty(privilege))
query = query.Where(c => (!_context.Privileges
.Include(p => p.PrivilegeType)
.Any(p => p.PrivilegeValue == 1
&& p.PrivilegeType.Code == privilege
&& p.ObjectTypeId == objectTypeId
&& p.ObjectId == c.CategoryId))
||
_context.Privileges
.Include(p => p.PrivilegeType)
.Any(p => p.PrivilegeValue == 1
&& p.PrivilegeType.Code == privilege
&& p.ObjectTypeId == objectTypeId
&& p.ObjectId == c.CategoryId
&& (p.UserId == userId || _context.UserGroups.Select(ug => ug.UserID).Contains(userId))));
以下是我想要做的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))
)
))
答案 0 :(得分:1)
问题:
正如评论中所述,Category
和Privilege
之间没有外键关系。存在一种软关系:Privilege.ObjectID
指向 a 表的 主键。问题是您的子查询与类别和权限无关,因为CategoryID
未被使用。 任何类别的条件为true或false。
Include
仅在填充查询结果中的实体的导航属性时才有效。换句话说,Privileges.Include(p => p.PrivilegeType)
仅在返回Privileges
时有效。除此之外,Include
不能被过滤,因此不能用作过滤条件。
所以要做的第一件事就是:匹配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)))
);
答案 1 :(得分:0)
您当前的查询实际上并未执行与不同实体相关的任何类型的过滤:
return _context.Categories.Where(c =>
_context.Privileges
.Include(p => p.PrivilegeType)
Where(p => p.PrivilegeType.Code == "code").Any()).ToList();
如果数据库中的Categories
个实体的Privilege
值为PrivilegeType.Code
,则此代码将转到数据库并获取数据库中的所有code
Categories
。这不会过滤任何内容,只会返回所有 c
。
同样如@dcg的评论中所述,您没有在第一个lambda表达式中使用_context
变量,我相信这是您作为C#对象接收的实际异常的原因(在此case _context.Categories.Where(c => c.Privileges.Any(p => p.PrivilegeType.Code == "code")).ToList();
)无法传递到where表达式。
决议将是:
Categories
这假设您在Privileges
和Categories
之间存在外键关系。如果不这样做,那么您将需要重新构建这两个表的关联方式,或者提供有关您尝试使用这两个实体加入的更多详细信息。
编辑:
在您的帖子中澄清之后,上述查询是您要查找的内容,但您需要实际映射Privileges
和Categories
实体之间的关系。在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);
}
}
实体映射配置中执行以下操作:
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
这将允许您在Category和Privilege之间定义1- *的关系,而不要求Privilege实际上具有任何类型的关系回到Category。作为结果,您将能够编写这样的复杂查询。
编辑:
我试图重新创建您的SQL查询(虽然我必须从上面代码的结构构建我自己的本地上下文,但它可能不完全准确)
我相信这将生成与查询相同的结果集。它可能不会生成相同的SQL,但结果应该相同。
import {
StackNavigator,
} from 'react-navigation'
import SignupForm2 from './SignupForm2'
const App = StackNavigator({
SignupForm2: { screen: SignupForm2 },
});
export default class SignupForm extends Component {
render () {
const { navigate } = this.props.navigation
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigate('SignupForm2', { name: 'SignupForm2' })
}
/>
)
}
}