在 ServiceStack AutoQuery 中多次加入相同的 table
Joining the same table multiple times in ServiceStack AutoQuery
我正在尝试对 table A 使用 ServiceStack 的 Auto Query 功能,它多次引用另一个 table B,但无法使其正常工作。
其根源似乎是 AutoQuery 生成联接时没有为联接的 table 设置别名,从而导致列不明确。它对 SQL Server 和 Sqlite 都失败并出现类似的错误。我一直没能找到解决这个问题的方法。
这基本上就是我所做的:
public class Purchase
{
public int Id { get; set; }
public string Description { get; set; }
[References(typeof(Person))]
public int SellerId { get; set; }
[References(typeof(Person))]
public int BuyerId { get; set; }
[Reference]
public Person Buyer { get; set; }
[Reference]
public Person Seller { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/autoquery")]
public class AutoQueryRequest : QueryBase<Purchase, CustomPurchase>, IJoin<Purchase, Seller>, IJoin<Purchase, Buyer>
{ }
完整代码可以在这里找到:
https://gist.github.com/AVee/0cb0dc1912698fcc43df
OrmLite(以及扩展的 AutoQuery)不支持 Table JOIN 的自定义别名,因此您将无法通过 AutoQuery 查询单个 table。
虽然正常用例:
[Route("/purchase/query")]
public class QueryPurchase : QueryBase<Purchase>
{
public int Id { get; set; }
}
client.Get(new QueryPurchase { Id = 1 }).PrintDump();
这将加入并填充 multiple self references:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
OrmLite 中还有一个新的 CustomJoin
API,允许您指定自己的 。
使用自定义 AutoQuery 实现
由于您无法查询多个自引用的 table,一种方法是使用自定义自动查询实现,您可以在自定义中查询子 table ID自动查询实现。
为此,我们将创建一个额外的 "backing" AutoQuery DTO QueryPurchase
,其中包含 AutoQuery 可以处理的属性,而 CustomPurchase
AutoQuery 仍然是 public 面向 API 您要为此服务公开,例如:
[Alias("Purchase")]
public class CustomPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
public string SellerName { get; set; }
public string BuyerName { get; set; }
}
public class QueryPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
public List<int> BuyerIds { get; set; }
public List<int> SellerIds { get; set; }
}
并且在您的自定义 AutoQuery 实现中,您可以获取适当的买家和卖家 ID,并将它们添加到支持 QueryPurchase
查询中,例如:
public QueryResponse<Purchase> Any(CustomPurchase request)
{
var qPurchase = request.ConvertTo<QueryPurchase>();
if (request.BuyerName != null)
{
qPurchase.BuyerIds = Db.Column<int>(Db.From<Person>()
.Where(x => x.Name == request.BuyerName)
.Select(x => x.Id));
}
if (request.SellerName != null)
{
qPurchase.SellerIds = Db.Column<int>(Db.From<Person>()
.Where(x => x.Name == request.SellerName)
.Select(x => x.Id));
}
var q = AutoQuery.CreateQuery(qPurchase, Request.GetRequestParams());
return AutoQuery.Execute(qPurchase, q);
}
AutoQuery 理解 BuyerIds
等集合属性,并对 BuyerId
.
执行适当的查询
所以现在调用此服务时:
client.Get(new CustomPurchase { BuyerName = "Rose Tyler" }).PrintDump();
它将打印所需的内容:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
附加自定义条件
本着类似的精神,另一种方法是向 AutoQuery 本身添加自定义条件,为此我们不再需要 BuyerIds
或 SellerIds
属性,例如:
public class QueryPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
}
QueryPurchase
DTO 包含 AutoQuery 可以处理的 Purchase
table 属性减去需要特例的 SellerName
和 BuyerName
,例如:
public QueryResponse<Purchase> Any(CustomPurchase request)
{
//Copy only the properties that AutoQuery can handle
var qPurchase = request.ConvertTo<QueryPurchase>();
var q = AutoQuery.CreateQuery(qPurchase, Request.GetRequestParams());
//Add Custom SQL Conditions for each Custom Query
if (request.BuyerName != null)
q.UnsafeWhere("BuyerId IN (SELECT Id FROM Person WHERE Name = {0})",
request.BuyerName);
if (request.SellerName != null)
q.UnsafeWhere("SellerId IN (SELECT Id FROM Person WHERE Name = {0})",
request.SellerName);
return AutoQuery.Execute(qPurchase, q);
}
这类似于上面的自定义 AutoQuery 实现,只是它被添加到单个 AutoQuery 查询中。
同样调用此服务:
csharp
client.Get(new CustomPurchase { BuyerName = "Rose Tyler" }).PrintDump();
同时打印所需的:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
为了支持这一点,OrmLite 的 SqlExpression
有一个新的 UnsafeWhere
API,以便能够像子 [=82] 添加未经验证的原始 SQL =] 在上面添加。参数仍然会被转义,这将阻止任何 SQL 注入。此更改可从 v4.0.37+ 获得,现在是 available on MyGet.
我正在尝试对 table A 使用 ServiceStack 的 Auto Query 功能,它多次引用另一个 table B,但无法使其正常工作。
其根源似乎是 AutoQuery 生成联接时没有为联接的 table 设置别名,从而导致列不明确。它对 SQL Server 和 Sqlite 都失败并出现类似的错误。我一直没能找到解决这个问题的方法。
这基本上就是我所做的:
public class Purchase
{
public int Id { get; set; }
public string Description { get; set; }
[References(typeof(Person))]
public int SellerId { get; set; }
[References(typeof(Person))]
public int BuyerId { get; set; }
[Reference]
public Person Buyer { get; set; }
[Reference]
public Person Seller { get; set; }
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
[Route("/autoquery")]
public class AutoQueryRequest : QueryBase<Purchase, CustomPurchase>, IJoin<Purchase, Seller>, IJoin<Purchase, Buyer>
{ }
完整代码可以在这里找到: https://gist.github.com/AVee/0cb0dc1912698fcc43df
OrmLite(以及扩展的 AutoQuery)不支持 Table JOIN 的自定义别名,因此您将无法通过 AutoQuery 查询单个 table。
虽然正常用例:
[Route("/purchase/query")]
public class QueryPurchase : QueryBase<Purchase>
{
public int Id { get; set; }
}
client.Get(new QueryPurchase { Id = 1 }).PrintDump();
这将加入并填充 multiple self references:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
OrmLite 中还有一个新的 CustomJoin
API,允许您指定自己的
使用自定义 AutoQuery 实现
由于您无法查询多个自引用的 table,一种方法是使用自定义自动查询实现,您可以在自定义中查询子 table ID自动查询实现。
为此,我们将创建一个额外的 "backing" AutoQuery DTO QueryPurchase
,其中包含 AutoQuery 可以处理的属性,而 CustomPurchase
AutoQuery 仍然是 public 面向 API 您要为此服务公开,例如:
[Alias("Purchase")]
public class CustomPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
public string SellerName { get; set; }
public string BuyerName { get; set; }
}
public class QueryPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
public List<int> BuyerIds { get; set; }
public List<int> SellerIds { get; set; }
}
并且在您的自定义 AutoQuery 实现中,您可以获取适当的买家和卖家 ID,并将它们添加到支持 QueryPurchase
查询中,例如:
public QueryResponse<Purchase> Any(CustomPurchase request)
{
var qPurchase = request.ConvertTo<QueryPurchase>();
if (request.BuyerName != null)
{
qPurchase.BuyerIds = Db.Column<int>(Db.From<Person>()
.Where(x => x.Name == request.BuyerName)
.Select(x => x.Id));
}
if (request.SellerName != null)
{
qPurchase.SellerIds = Db.Column<int>(Db.From<Person>()
.Where(x => x.Name == request.SellerName)
.Select(x => x.Id));
}
var q = AutoQuery.CreateQuery(qPurchase, Request.GetRequestParams());
return AutoQuery.Execute(qPurchase, q);
}
AutoQuery 理解 BuyerIds
等集合属性,并对 BuyerId
.
所以现在调用此服务时:
client.Get(new CustomPurchase { BuyerName = "Rose Tyler" }).PrintDump();
它将打印所需的内容:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
附加自定义条件
本着类似的精神,另一种方法是向 AutoQuery 本身添加自定义条件,为此我们不再需要 BuyerIds
或 SellerIds
属性,例如:
public class QueryPurchase : QueryBase<Purchase>
{
public int? Id { get; set; }
public string Description { get; set; }
}
QueryPurchase
DTO 包含 AutoQuery 可以处理的 Purchase
table 属性减去需要特例的 SellerName
和 BuyerName
,例如:
public QueryResponse<Purchase> Any(CustomPurchase request)
{
//Copy only the properties that AutoQuery can handle
var qPurchase = request.ConvertTo<QueryPurchase>();
var q = AutoQuery.CreateQuery(qPurchase, Request.GetRequestParams());
//Add Custom SQL Conditions for each Custom Query
if (request.BuyerName != null)
q.UnsafeWhere("BuyerId IN (SELECT Id FROM Person WHERE Name = {0})",
request.BuyerName);
if (request.SellerName != null)
q.UnsafeWhere("SellerId IN (SELECT Id FROM Person WHERE Name = {0})",
request.SellerName);
return AutoQuery.Execute(qPurchase, q);
}
这类似于上面的自定义 AutoQuery 实现,只是它被添加到单个 AutoQuery 查询中。
同样调用此服务:
csharp
client.Get(new CustomPurchase { BuyerName = "Rose Tyler" }).PrintDump();
同时打印所需的:
{
Offset: 0,
Total: 1,
Results:
[
{
Id: 1,
Description: Sonic Screwdriver,
SellerId: 2,
BuyerId: 1,
Buyer:
{
Id: 1,
Name: Rose Tyler
},
Seller:
{
Id: 2,
Name: Martha Jones
}
}
]
}
为了支持这一点,OrmLite 的 SqlExpression
有一个新的 UnsafeWhere
API,以便能够像子 [=82] 添加未经验证的原始 SQL =] 在上面添加。参数仍然会被转义,这将阻止任何 SQL 注入。此更改可从 v4.0.37+ 获得,现在是 available on MyGet.