[英]ServiceStack service request design
I am keen on using ServiceStack and have created a little test app with a simple customer service: 我热衷于使用ServiceStack,并使用简单的客户服务创建了一个小测试应用程序:
[Route("/customers/{id}")]
public class GetCustomer : IReturn<Customer>
{
public int Id { get; set; }
}
[Route("/customers/search")]
public class FindCustomers : IReturn<List<Customer>>
{
public string LastName { get; set; }
public int Age { get; set; }
public string? City { get; set; }
}
public class CustomerService : IService
{
public object Get(GetCustomer request)
{
var db = new WebServDb();
var customer = db.FirstOrDefault<Customer>("WHERE Id=@0", request.Id);
return customer;
}
public object Get(FindCustomers request)
{
var db = new WebServDb();
var customers = new List<Customer>();
if (request.City.HasValue)
customers = db.Fetch<Customer>("WHERE LastName=@0 AND Age=@1 AND City=@2", request.LastName, request.Age, request.City);
else
customers = db.Fetch<Customer>("WHERE LastName=@0 AND Age=@1", request.LastName, request.Age);
return customers;
}
}
The FindCustomers request DTO contains 3 properties that can be used to search for customers. FindCustomers请求DTO包含3个可用于搜索客户的属性。 Based on which properties are set I need to query the DB differently. 根据设置的属性,我需要以不同的方式查询数据库。 So what is the best way to do this? 那么最好的方法是什么? For example, if I add another property such as: 例如,如果我添加另一个属性,例如:
[Route("/customers/search")]
public class FindCustomers : IReturn<List<Customer>>
{
public string LastName { get; set; }
public int Age { get; set; }
public string? City { get; set; }
public string? ZipCode { get; set; }
}
to the FindCustomers DTO, I would also have to change the service Get method to: 到FindCustomers DTO,我还必须将服务的Get方法更改为:
public object Get(FindCustomers request)
{
var db = new WebServDb();
var customers = new List<Customer>();
if (request.City.HasValue && request.ZipCode.HasValue)
customers = db.Fetch<Customer>("WHERE LastName=@0 AND Age=@1 AND City=@2 AND ZipCode=@3", request.LastName, request.Age, request.City, request.ZipCode);
else if (request.City.HasValue)
customers = db.Fetch<Customer>("WHERE LastName=@0 AND Age=@1 AND City=@2", request.LastName, request.Age, request.City);
else
customers = db.Fetch<Customer>("WHERE LastName=@0 AND Age=@1", request.LastName, request.Age);
return customers;
}
So for each property I add/remove from the request DTO I need to modify my Get method. 因此,对于我从请求DTO添加/删除的每个属性,我都需要修改Get方法。 Is there better way do this? 有更好的方法吗? A more generic way to check for properties set and querying the DB? 检查属性集和查询数据库的更通用方法?
Would it be better to have specific request DTOs such as FindCustomersByLastNameCity , FindCustomersByLastNameZipCode , etc. as well as corresponding specific Get methods in the CustomerService ? 它会更好有具体要求的DTO如FindCustomersByLastNameCity,FindCustomersByLastNameZipCode,等,以及在相应的CustomerService具体Get方法?
Would it be better to have specific request DTOs such as FindCustomersByLastNameCity, FindCustomersByLastNameZipCode 最好有特定的请求DTO,例如FindCustomersByLastNameCity,FindCustomersByLastNameZipCode
I would avoid this if possible as it goes against the 'Message Based Services' benefits/approach encouraged by ServiceStack. 如果可能的话,我会避免这样做,因为这违反了ServiceStack鼓励的“基于消息的服务”的好处/方法。
Is there better way do this? 有更好的方法吗?
I don't know if I have a 'better way' but below are two options I have tried. 我不知道我是否有“更好的方式”,但以下是我尝试过的两个选择。 The second option is still a 'work in progress' and is meant to be more 'abstract' but I modified it to work with your example and to hopefully inspire other ideas. 第二个选项仍然是“进行中的工作”,它的意思是“更抽象”,但我对其进行了修改,以配合您的示例并希望激发其他想法。
Option 1 using ExpressionVisitor: 使用ExpressionVisitor的选项1:
public object Get(FindCustomers request)
{
var customers = new List<Customer>();
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<Customer>();
ev.Where(c => c.LastName == request.LastName).And(c => c.Age == request.Age);
AddOptionalFilters(ev, request);
customers = Db.Select<Customer>(ev);
return customers;
}
private void AddOptionalFilters(SqlExpressionVisitor<Customer> expressionVisitor, FindCustomers request)
{
if (request.City.HasValue)
{ expressionVisitor.Where(c => c.City == request.City); }
if (request.ZipCode.HasValue)
{ expressionVisitor.Where(c => c.ZipCode == request.ZipCode); }
}
Option 2 using the SqlBuilder from Dapper: 使用Dapper的SqlBuilder的选项2:
public object Get(FindCustomers request)
{
var customers = new List<Customer>();
var sqlAndParams = SqlAndParameters("SELECT * From Customers", request); //this returns a tuple of the sql string and the parameters
customers = Db.Query<Customer>(sqlAndParams.Item1, sqlAndParams.Item2);
return customers;
}
public virtual Tuple<String, IDictionary<string, object>> SqlAndParameters(string sql, FindCustomers request)
{
var builder = new SqlBuilder();
var selector = builder.AddTemplate(sql);
var sqlParams = new ExpandoObject() as IDictionary<string, object>;
builder.Where("LastName=@LastName");
sqlParams.Add("LastName", request.LastName);
builder.Where("Age=@Age");
sqlParams.Add("Age", request.Age);
if (request.City.HasValue)
{
builder.Where("City=@City");
sqlParams.Add("City", request.City);
}
if (request.ZipCode.HasValue)
{
builder.Where("ZipCode=@ZipCode");
sqlParams.Add("ZipCode", request.ZipCode);
}
return Tuple.Create(selector.RawSql, sqlParams);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.