ServiceStack ORMLite Sql 服务器 *可选过滤器

ServiceStack ORMLite Sql Server *optional filter

我需要在 ORMLite Sql 服务器中执行此操作 SQL:(如果我在参数中传递 0,那么我将删除过滤器,如 SQL:

declare @departmentId int = 0; 
declare @projectTaskStatusId int = 0; 
select * from ProjectTask t
join Project p on p.ProjectId = t.ProjectId     
where  
(p.DepartmentId = @departmentId or @departmentId = 0) and 
(t.ProjectTaskStatusId = @projectTaskStatusId or @projectTaskStatusId = 0)

我在下面创建了这段代码,但它不起作用,在 ORMLite SQL 服务器中执行此操作的最佳方法是什么?

dbCon.LoadSelectAsync(x => (x.Project.DepartmentId == departmentId || departmentId == 0) && (x.ProjectTaskStatusId == projectTaskStatusId || projectTaskStatusId == 0));

我可以使用下面的代码让它工作(但这是使用 Lambda 而不是直接在 OrmLite 中:

var tasks = await dbCon.LoadSelectAsync<ProjectTask>(x => x);
return tasks.Where(x => (departmentId == 0 || x.Project.DepartmentId.Equals(departmentId)) && (projectTaskStatusId == 0 || x.ProjectTaskStatusId.Equals(projectTaskStatusId)));

在你们的帮助下,我可以做下面的解决方案,但是,我认为它是昂贵的,因为我不能只使用 SelectAsync 的 LoadReferences,然后我必须做一个 foreach 来手动加载每个参考:

var query = dbCon.From<ProjectTask>()
                    .Join<ProjectTask, Project>((pt, p) => pt.ProjectId == p.Id)
                    .Where<Project>(p => p.DepartmentId == departmentId || departmentId == 0)
                    .And<ProjectTask>(pt => pt.ProjectTaskStatusId == projectTaskStatusId || projectTaskStatusId == 0);

var tasks = await dbCon.SelectAsync(query);

// Load the references
foreach (var item in tasks)
{
    if (item.ProjectId > 0)
        item.Project = await dbCon.SingleByIdAsync<Project>(item.ProjectId);

    if (item.AssignedToId > 0)
        item.AssignedTo = await dbCon.SingleByIdAsync<Employee>(item.AssignedToId);

    if (item.RequestedById > 0)
        item.RequestedBy = await dbCon.SingleByIdAsync<Employee>(item.RequestedById);

    if (item.ProjectTaskStatusId > 0)
        item.ProjectTaskStatus = await dbCon.SingleByIdAsync<ProjectTaskStatus>(item.ProjectTaskStatusId);
}

return tasks;

我现在手边没有代码,所以我可能对语法有点偏离,但我认为以下代码将转换为等效查询。

var query = db.From<ProjectTask>()
              .Join<ProjectTask, Project>((pt, p) => pt.ProjectId == p.ProjectId)
              .Where<Project>(p => p.DepartmentId == departmentId || departmentId == 0)
              .And<ProjectTask>(pt => pt.ProjectTaskStatusId == statusId || statusId == 0);

var tasks = await dbCon.SelectAsync<ProjectTask>(query);

免责声明:这是针对 Servicestack.OrmLite 4.0+ 版及其新的漂亮的 SqlExpression 类。

更新:

好的,我知道你现在想做什么了。
是的,在这样的 for 循环中加载引用并不是非常有效的解决方案。我不确定为什么 LoadSelect 方法不起作用(如果你对它进行了良好的重现测试,你可能想将其报告为一个可能的错误),但可能有一个解决方法。

如果你深入研究 OrmLite 源代码并检查它实际做了什么,你可以看到在 LoadSelect 的掩护下实际做的是查询首先是 运行 并且然后 OrmLite 遍历模型定义并发出

形式的查询

SELECT columns FROM table WHERE id IN (originalquery)

对于每个参考文献。然后它获取该查询的结果并将结果连接到引用。因此,OrmLite 在使用 LoadSelect 时实际上会在这里发出多个查询,尽管每个引用 1 个查询而不是每个对象每个引用 1 个查询,这要好得多。

您可以手动执行此策略。虽然这会有点麻烦......我现在不会给你任何代码,因为我现在没有一台装有 VS 的电脑,而且它更高级一些,所以我不我想我能猜到这个。

但是,您真的需要所有这些参考资料吗?我现在只是在猜测,但这看起来像是您一次性加载的大量数据。您真的需要所有这些参考文献和专栏,还是只需要其中的几个?如果您真的只需要其中的几个,您可能想要连接到一个自定义模型中,而只包含您实际需要的列。这将是性能最高的选项,因为您将能够在一个查询中完成此操作,并且只传输您实际需要的数据而不是所有数据。但我不知道你是如何使用这些数据的,所以这可能不是一个好的选择。 :)

但是如前所述,您可能在 LoadSelect 中发现了错误!我强烈建议您将它添加到问题跟踪器中,看看他们是否会修复它——根据我的经验,ServiceStack 在响应和修复错误方面确实非常快。特别是如果你给他们一个可重现的单元测试(你可以很容易地从你的代码中提取它)。

https://github.com/ServiceStack/Issues/issues