C# 在单个实体上计算true的System.Linq表达式

C# 在单个实体上计算true的System.Linq表达式,c#,linq,C#,Linq,我正试图删掉一些lambda表达式以获得担保权。是否可以采用lamda表达式并将其应用于单个实体以获得true 比如说我有一个人和一个文档文件夹 Expression<Func<Person, bool>> CanSeePerson() { return c => !c.IsPrivate; } 我知道如何在iqueryable上使用where,但看不到如何将表达式树应用于单个值 这会引发错误:无法创建“Person”类

我正试图删掉一些lambda表达式以获得担保权。是否可以采用lamda表达式并将其应用于单个实体以获得true

比如说我有一个人和一个文档文件夹

    Expression<Func<Person, bool>> CanSeePerson()
    {
        return c =>  !c.IsPrivate;
    }
我知道如何在iqueryable上使用where,但看不到如何将表达式树应用于单个值



这会引发错误:无法创建“Person”类型的常量值。在此上下文中仅支持基本类型(“如Int32、String和Guid”)

Expression<Func<DocumentFolder, bool>> CanSeeFolder()
    {
        return c => !c.IsPrivate &&_entities.Persons.Where(x => x.Id == c.Owner.Id).Any(CanSeePerson());
}
Expression CanSeeFolder()
{
返回c=>!c.IsPrivate&&&u entities.Persons.Where(x=>x.Id==c.Owner.Id).Any(canseperson());
}

区别似乎是基于将IQueryable直接放在语句中。这也不起作用

Expression<Func<DocumentFolder, bool>> CanSeeFolder()
    {
        return c => !c.IsPrivate &&_entities.Persons.Where(CanSeePerson()).Contains(c.User);
    }
Expression CanSeeFolder()
{
返回c=>!c.IsPrivate&&&u entities.Persons.Where(canseperson()).Contains(c.User);
}
但这确实有效

Expression<Func<DocumentFolder, bool>> CanSeeFolder()
        {
            var canSeePersons = _entities.Persons.Where(CanSeePerson());
            return c => !c.IsPrivate && canSeePersons.Contains(c.User);
        }
Expression CanSeeFolder()
{
var CanSeePerson=_entities.Persons.Where(CanSeePerson());
返回c=>!c.IsPrivate&&cansepersons.Contains(c.User);
}
p、 我知道我用这个stackoverflow格式很烂,哈哈


之所以这样做,是因为不能在表达式中转换和使用CanSeePerson()函数。当您将canSeePersons变量放入函数中时,您将放入一个可在表达式中使用的iQueryable类型。使用“var”将其卷积一点。

表达式树一次仅应用于LINQ表达式中逻辑上的单个值

如果您想在以后将其应用于单个值的过程中,您可以使用:

// This can be cached
Func<DocumentFolder, bool> canSeeFolderDelegate = CanSeeFolder().Compile();

DocumentFolder folder = ...; // Get the value from somewhere
if (canSeeFolderDelegate(folder))
{
    // Yes, you can see that folder
}
//这可以缓存
Func canSeeFolderDelegate=CanSeeFolder().Compile();
DocumentFolder文件夹=…;//从某处获取值
如果(可参见文件夹委派(文件夹))
{
//是的,你可以看到那个文件夹
}
表达式树一次仅应用于LINQ表达式中的单个值(逻辑上)

如果您想在以后将其应用于单个值的过程中,您可以使用:

// This can be cached
Func<DocumentFolder, bool> canSeeFolderDelegate = CanSeeFolder().Compile();

DocumentFolder folder = ...; // Get the value from somewhere
if (canSeeFolderDelegate(folder))
{
    // Yes, you can see that folder
}
//这可以缓存
Func canSeeFolderDelegate=CanSeeFolder().Compile();
DocumentFolder文件夹=…;//从某处获取值
如果(可参见文件夹委派(文件夹))
{
//是的,你可以看到那个文件夹
}
啊,你想为单个实体评估它吗

var func = CanSeeFolder().Compile(); // <=== store and re-use this;
                                     //      this isn't free
bool canSee = func(obj);
但这可能仍然会在链中的某个位置执行
编译
,因此您也可以使用更直接的代码(在顶部)


重新编辑评论:

要在数据库中对此进行评估,您需要一个限制,例如:

bool canSee = db.Folders.Where(f => f.FolderId == id)
                .Where(CanSeeFolder()).Any();
这将我们限制为一行,然后添加额外的筛选器。

啊,您想为单个实体计算它吗

var func = CanSeeFolder().Compile(); // <=== store and re-use this;
                                     //      this isn't free
bool canSee = func(obj);
但这可能仍然会在链中的某个位置执行
编译
,因此您也可以使用更直接的代码(在顶部)


重新编辑评论:

要在数据库中对此进行评估,您需要一个限制,例如:

bool canSee = db.Folders.Where(f => f.FolderId == id)
                .Where(CanSeeFolder()).Any();

这将我们限制为一行,然后添加额外的筛选器。

您定义了一个
表达式来解决您的问题。诀窍是简单地将对象列表转换为要过滤的列表。这并不总是可能的,但很多时候是可能的。你只需要有点创意:-)

使用扩展方法时,您可以很容易地想出一个解决方案,使您能够做到这一点:

var visibleFolders = Entities.DocumentFolder.WhereCanSeeFolder();
这是(完全干燥的)解决方案:

public static class SecurityExtensions
{
    public static IQueryable<DocumentFolder> WhereCanSeeFolder(
        this IQueryable<DocumentFolder> folders)
    {
        var visibleOwners = folders.Select(f => f.Owner)
            .Where(CanSeePerson);

        return
            from folder in folders.Where(CanSeeFolder)
            where visibleOwners.Contains(folder.Owner)
            select folder;
    }

    private static readonly Expression<Func<DocumentFolder, bool>>
        CanSeeFolder = folder => !folder.IsPrivate;

    private static readonly Expression<Func<Person, bool>>
        CanSeePerson = person => !person.IsPrivate;
}
公共静态类SecurityExtensions
{
公共静态IQueryable where可查看文件夹(
这是一个可用的文件夹)
{
var visibleowner=文件夹。选择(f=>f.Owner)
.何处(坎瑟弗森);
返回
来自文件夹中的文件夹。其中(CanSeeFolder)
其中visibleOwners.Contains(folder.Owner)
选择文件夹;
}
私有静态只读表达式
CanSeeFolder=文件夹=>!folder.IsPrivate;
私有静态只读表达式
canseperson=person=>!person.IsPrivate;
}

我希望这有帮助。

您定义了一个
表达式来解决您的问题。诀窍是简单地将对象列表转换为要过滤的列表。这并不总是可能的,但很多时候是可能的。你只需要有点创意:-)

使用扩展方法时,您可以很容易地想出一个解决方案,使您能够做到这一点:

var visibleFolders = Entities.DocumentFolder.WhereCanSeeFolder();
这是(完全干燥的)解决方案:

public static class SecurityExtensions
{
    public static IQueryable<DocumentFolder> WhereCanSeeFolder(
        this IQueryable<DocumentFolder> folders)
    {
        var visibleOwners = folders.Select(f => f.Owner)
            .Where(CanSeePerson);

        return
            from folder in folders.Where(CanSeeFolder)
            where visibleOwners.Contains(folder.Owner)
            select folder;
    }

    private static readonly Expression<Func<DocumentFolder, bool>>
        CanSeeFolder = folder => !folder.IsPrivate;

    private static readonly Expression<Func<Person, bool>>
        CanSeePerson = person => !person.IsPrivate;
}
公共静态类SecurityExtensions
{
公共静态IQueryable where可查看文件夹(
这是一个可用的文件夹)
{
var visibleowner=文件夹。选择(f=>f.Owner)
.何处(坎瑟弗森);
返回
来自文件夹中的文件夹。其中(CanSeeFolder)
其中visibleOwners.Contains(folder.Owner)
选择文件夹;
}
私有静态只读表达式
CanSeeFolder=文件夹=>!folder.IsPrivate;
私有静态只读表达式
canseperson=person=>!person.IsPrivate;
}

我希望这能有所帮助。

我可能遗漏了一些简单的东西我可能遗漏了一些简单的东西如果你编译它,那么它就不再是一个expression@Kyle:当然可以,但你只是想在本地评估一下,对吗?如果需要,可以保留表达式并在需要时编译它。你认为把它仅仅作为一种表达有什么好处?鉴于您对Marc的回答的评论,听起来您有一些要求没有告诉我们。基本上,你需要给我们提供更多的背景。我想我是第一次放弃了清晰的想法。我道歉。是的,它必须保留为表达式,以便我可以使用实体框架将其发送到数据库4@Kyle:您最初打算如何“将其发送到数据库”?使用带有