服务堆栈服务请求设计

本文关键字:服务 请求 堆栈 | 更新日期: 2023-09-27 18:30:59

我热衷于使用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;
        }
    }

查找客户请求 DTO 包含 3 个可用于搜索客户的属性。根据设置的属性,我需要以不同的方式查询数据库。那么最好的方法是什么呢?例如,如果我添加另一个属性,例如:

 [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; }
    }

对于 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;
  }

因此,对于我在请求 DTO 中添加/删除的每个属性,我需要修改我的 Get 方法。有没有更好的方法?检查属性集和查询数据库的更通用方法?

客户服务中拥有特定的请求DTO,例如FindCustomersByLastNameCity,FindCustomersByLastNameZipCode等,以及相应的特定Get方法会更好吗?

服务堆栈服务请求设计

是否有特定的请求 DTO 会更好,例如 FindCustomersByLastNameCity、FindCustomersByLastNameZipCode
如果可能的话,我会避免这种情况,因为它违背了ServiceStack鼓励的"基于消息的服务"的好处/方法。

有没有更好的方法?
我不知道我是否有"更好的方法",但以下是我尝试过的两种选择。第二个选项仍然是"正在进行的工作",旨在更加"抽象",但我对其进行了修改以与您的示例一起使用,并希望激发其他想法。

选项 1 使用 ExpressionVisitor:

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); }
} 

选项 2 使用 Dapper 中的 SqlBuilder

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);
}