ServiceStack - [参考]或[忽略]?

时间:2016-03-21 14:08:03

标签: servicestack ormlite-servicestack

我们有一个DTO - 员工 - 有许多(> 20)相关的DTO和DTO集合。对于“返回JSON的大小”原因,我们将这些关系标记为[忽略]。然后由客户端填充他们想要使用其他REST调用的任何相关DTO。

我们已经尝试了几项方法来满足客户希望获得一些相关员工信息的愿望,但不是全部:

我们创建了一个新的DTO - EmployeeLite - 它具有使用“RelatedTableNameRelatedFieldName”方法定义的请求最多的字段,并使用了QueryBase重载并且运行良好。

我们还尝试向请求DTO添加属性 - “引用” - 这是客户端要填充的相关DTO的逗号分隔列表。然后,我们迭代响应并使用相关的DTO或List填充每个Employee。在迭代大型List时,关注的是性能。

我们想知道是否有建议的方法来解决我们想要做的事情?

感谢您提出的任何建议。

更新

以下是我们的请求DTO的一部分:

[Route("/employees", "GET")]
public class FindEmployeesRequest : QueryDb<Employee> {
    public int? ID { get; set; }
    public int[] IDs { get; set; }
    public string UserID { get; set; }
    public string LastNameStartsWith { get; set; }
    public DateTime[] DateOfBirthBetween { get; set; }
    public DateTime[] HireDateBetween { get; set; }
    public bool? IsActive { get; set; }
}

该服务没有代码(使用QueryDb自动化),所以我添加了一些来尝试“合并”方法:

public object Get(FindEmployeesRequest request) {
    var query = AutoQuery.CreateQuery(request, Request.GetRequestParams());

    QueryResponse<Employee> response = AutoQuery.Execute(request, query);

    if (response.Total > 0) {
        List<Clerkship> clerkships = Db.Select<Clerkship>();

        response.Results.Merge(clerkships);
    }

    return response;
}

此操作因Could not find Child Reference for 'Clerkship' on Parent 'Employee'

而失败

因为在员工中我们有:

    [Ignore]
    public List<Clerkship> Clerkships { get; set; }

我们之所以这样做是因为我们不希望每次请求都有“Clerkships”。如果我将[Ignore]更改为[Reference]我不需要服务中的上述代码 - 列表会自动显示。因此,似乎.Merge仅适用于我们不想做的[Reference]

我不确定如何在AutoQuery服务中使用“自定义加载引用”方法。而且,AFAIKT,“自定义字段”方法不能用于相关的DTO,仅适用于基表中的字段。

更新2:

LoadSelect include[]对我们来说效果很好。我们现在试图涵盖查询字符串中使用?fields=但客户端不请求相关DTO的ID字段的情况:

public partial class Employee {
    [PrimaryKey]
    [AutoIncrement]
    public int ID { get; set; }
    .
    .
    .
    [References(typeof(Department))]
    public int DepartmentID { get; set; }
    .
    .
    .

public class Department {
    [PrimaryKey]
    public int ID { get; set; }
    public string Name { get; set; }
    .
    .
    .
}

所以,对于请求

/employees?fields=id,departmentid

我们会在回复中得到部门。但是对于请求

/employees?fields=id

我们不会在回复中得到部门。

我们正在尝试通过在执行query.SelectExpression之前修改, "Employee"."DepartmentID"并将SELECT添加到Db.LoadSelect来为请求者“安静地”修复此问题。调试显示正在修改query.SelectExpression,但根据SQL事件探查器,"Employee"."DepartmentID"未被选中。

我们应该做些什么来将"Employee"."DepartmentID"添加到SELECT?

感谢。

更新3:

Employee表有三个1:1关系 - EmployeeType,Department和Title:

public partial class Employee {
    [PrimaryKey]
    [AutoIncrement]
    public int ID { get; set; }

    [References(typeof(EmployeeType))]
    public int EmployeeTypeID { get; set; }

    [References(typeof(Department))]
    public int DepartmentID { get; set; }

    [References(typeof(Title))]
    public int TitleID { get; set; }
    .
    .
    .
}

public class EmployeeType {
    [PrimaryKey]
    public int ID { get; set; }
    public string Name { get; set; }
}

public class Department {
    [PrimaryKey]
    public int ID { get; set; }
    public string Name { get; set; }

    [Reference]
    public List<Title> Titles { get; set; }
}

public class Title {
    [PrimaryKey]
    public int ID { get; set; }
    [References(typeof(Department))]
    public int DepartmentID { get; set; }
    public string Name { get; set; }
}

4.0.55的最新更新允许:

/employees?fields=employeetype,department,title

我收回所有Employee表字段以及三个相关的DTO - 有一个奇怪的东西 - Employee的ID字段填充了Employee的TitleID值(我想我们之前看过这个?)。

此请求修复了异常:

/employees?fields=id,employeetypeid,employeetype,departmentid,department,titleid,title

但我丢失了所有其他员工字段。

这听起来像是“有你的蛋糕,也吃它”的要求,但有没有办法可以获得所有的员工字段和选择性相关的DTO?类似的东西:

/employees?fields=*,employeetype,department,title

1 个答案:

答案 0 :(得分:4)

AutoQuery Customizable Fields

不确定这是否相关,但AutoQuery内置了Customizing which fields to return Merge disconnected POCO Results选项的支持。

merge disconnected POCO results

由于您没有提供任何源代码,因此不清楚您尝试实现的目标或现有解决方案效率低下的地方,但您并不想成为执行任何?fields=Field1,Field2 SELECT查询。如果您是,请查看如何Custom Load References在一起,这将允许您根据使用OrmLite引用定义的关系合并来自单独查询的结果,例如,下面的示例使用2个不同的查询来将Customers与其订单连接起来:

N+1

this

当您致电OrmLite的//Select Customers who've had orders with Quantities of 10 or more List<Customer> customers = db.Select<Customer>(q => q.Join<Order>() .Where<Order>(o => o.Qty >= 10) .SelectDistinct()); //Select Orders with Quantities of 10 or more List<Order> orders = db.Select<Order>(o => o.Qty >= 10); customers.Merge(orders); // Merge disconnected Orders with their related Customers API时,您可以选择性地控制OrmLite应加载的引用,例如:

Load*

在AutoQuery中使用自定义加载引用

您可以自定义AutoQuery请求,以便在自定义AutoQuery实现中使用var customerWithAddress = db.LoadSingleById<Customer>(customer.Id, include: new[] { "PrimaryAddress" }); 而不是Db.Select来返回任何引用,例如:

Db.LoadSelect

同样,如果您只想有选择地加载一个或多个引用,您可以更改LoadSelect以传入public object Get(FindEmployeesRequest request) { var q = AutoQuery.CreateQuery(request, Request); var response = new QueryResponse<Employee> { Offset = q.Offset.GetValueOrDefault(0), Results = Db.Select(q), Total = (int)Db.Count(q), }; return response; } 数组,其中只包含您想要包含的引用字段,例如:

include: