2

私は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;
        }
    }

FindCustomersリクエスト DTO には、顧客の検索に使用できる 3 つのプロパティが含まれていますどのプロパティが設定されているかに基づいて、DB に異なるクエリを実行する必要があります。では、これを行う最善の方法は何ですか? たとえば、次のような別のプロパティを追加するとします。

 [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メソッドを変更する必要があります。これを行うより良い方法はありますか?プロパティ セットと DB のクエリを確認するより一般的な方法は?

FindCustomersByLastNameCityFindCustomersByLastNameZipCodeなどの特定のリクエスト DTOと、対応するCustomerServiceの特定の Get メソッドを用意したほうがよいでしょうか?

4

1 に答える 1

5

FindCustomersByLastNameCity、FindCustomersByLastNameZipCode などの特定のリクエスト DTO を使用する方がよいでしょうか。ServiceStack
によって推奨される「メッセージ ベースのサービス」のメリット/アプローチに反するため、可能であればこれを避けます。

これを行うより良い方法はありますか?
「より良い方法」があるかどうかはわかりませんが、以下は私が試した2つのオプションです。2番目のオプションはまだ「進行中の作業」であり、より「抽象的」であることを意図していますが、あなたの例で動作し、うまくいけば他のアイデアを刺激するように修正しました.

オプション 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); }
} 

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);
}
于 2013-09-12T18:11:54.657 に答える