2013-06-26 25 views
6

Tôi tự hỏi nếu JoinSqlBuilder ServiceStack.OrmLite của phép để xây dựng các truy vấn đơn giản sau đây:Liệu ServiceStack.OrmLite.JoinSqlBuilder cho phép để xây dựng một truy vấn đơn giản

SELECT * FROM Table1 a 
    INNER JOIN Table2 b ON ... 
    WHERE a.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3); 

Vấn đề là xây dựng (a.Column2 = 2 OR b.Column3 = 3) phần. JoinSqlBuilder có danh sách các phương thức như Where<T>, And<T>, Or<T> cho phép thêm điều kiện cho truy vấn.

Ví dụ, nếu tôi làm:

builder 
    .Join(...) 
    .Where<Table1Poco>(a => a.Column1 == 1) 
    .And<Table1Poco>(a => a.Column2 == 2) 
    .Or<Table2Poco>(a => a.Column3 == 3) 
    ...; 

tôi sẽ nhận được:

... WHERE a.Column1 = 1 AND a.Column2 = 2 OR b.Column3 = 3; 

Có cách nào để xây dựng a.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3) với ServiceStack.OrmLite?

Tôi biết rằng tôi có thể làm điều đó với sql thô nhưng nó không phải là một tùy chọn vì tôi không muốn mất an toàn loại và phương ngữ độc lập.

+1

Theo như tôi biết nó không có ở đó. Và Micro-orm là tốt cho loại này hoặc những thứ. Bạn có thể quay lại truy vấn cũ đơn giản cho các tình huống phức tạp. Hy vọng rằng bạn biết truy vấn () chức năng bạn có thể sử dụng và vượt qua một tham số nếu bạn muốn. – kunjee

Trả lời

4

Tôi đồng ý với kunjee rằng đây không thực sự là điều mà Micro-orm phù hợp. Với điều đó đã nói, tôi có thể nghĩ đến 2 lựa chọn tiềm năng ... không phải thứ gì thực sự là thứ tôi muốn giới thiệu trên ORM (EF hoặc nHibernate) đầy đủ như một giải pháp. Nhưng, có lẽ điều này sẽ giúp thu hút các lựa chọn tốt hơn.

Tùy chọn 1 - Xây dựng chuỗi 'Where clause string' bằng cách sử dụng sự phản chiếu để giữ an toàn kiểu '. Bạn sẽ vẫn cần phải viết một chút SQL.

Ví dụ

var jn = new JoinSqlBuilder<Table1, Table2>(); 
jn = jn.Join<Table1, Table2>(s => s.Column1, d => d.Field1); 

//using ExpressionVisitor because I didn't see a way to allow a Where clause string parameter to be used 
//on a JoinSqlBuilder method 
var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<Table1>(); 
ev.Where(
    SqlHelper.ToSqlField<Table1>(x => x.Column1) + "={0} AND (" + 
    SqlHelper.ToSqlField<Table1>(x => x.Column2) + "={1} OR " + SqlHelper.ToSqlField<Table2>(x => x.Column3) + 
     "={2})", "1", "2", "3"); 

var sql = jn.ToSql() + ev.WhereExpression; 

Helper Lớp

public static class SqlHelper 
{ 
    public static string ToSqlField<T>(Expression<Func<T, object>> expression) 
    { 
     //This should return something like 'Table1.Column1' 
     return typeof(T).Name + "." + GetMemberInfo(expression).Name; 
    } 

    // Stolen from FluentNHibernate.ReflectionUtility 
    public static MemberInfo GetMemberInfo<TEntity>(Expression<Func<TEntity, object>> expression) 
    { 
     MemberInfo memberInfo = null; 

     switch (expression.Body.NodeType) 
     { 
      case ExpressionType.Convert: 
       { 
        var body = (UnaryExpression)expression.Body; 
        if (body.Operand is MethodCallExpression) 
        { 
         memberInfo = ((MethodCallExpression)body.Operand).Method; 
        } 
        else if (body.Operand is MemberExpression) 
        { 
         memberInfo = ((MemberExpression)body.Operand).Member; 
        } 
       } 
       break; 
      case ExpressionType.MemberAccess: 
       memberInfo = ((MemberExpression)expression.Body).Member; 
       break; 
      default: 
       throw new ArgumentException("Unsupported ExpressionType", "expression"); 
     } 

     if (memberInfo == null) { throw new ArgumentException("Could not locate MemberInfo.", "expression"); } 

     return memberInfo; 
    } 
} 

Lựa chọn 2 - Mess/ô nhiễm Lớp học của bạn và tắt các tiền tố bảng trong một ExpressionVisitor cho phép SQL đúng là được tạo. Điều này sẽ hoàn toàn nổ tung nếu 2 lớp có cùng thuộc tính và được sử dụng trong mệnh đề Where.

//Modify Table1 to include a reference to Table2 
public class Table1 
{ 
    public string Column1 { get; set; } 
    public string Column2 { get; set; } 

    [ServiceStack.DataAnnotations.Ignore] 
    public Table2 Table2 { get; set; } 
} 

var ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<Table1>(); 
ev.PrefixFieldWithTableName = false; 

var jn = new JoinSqlBuilder<Table1, Table2>(); 
jn = jn.Join<Table1, Table2>(s => s.Column1, d => d.Field1); 
ev.Where(x => x.Column1 == "1"); 
ev.Where(x => x.Column2 == "2" || ((Table2)x.Table2).Column3 == "3"); //do cast to avoid InvalidOperationException 

var sql = jn.ToSql() + ev.WhereExpression; 
+0

Cảm ơn bạn đã có câu trả lời hoàn chỉnh. Tôi đã đến smth tương tự như tùy chọn 1 - để viết trình xây dựng truy vấn của riêng tôi trên ExpressionVisitor của OrmLite. Tôi không đồng ý rằng việc tham gia không phải là một nhiệm vụ cho vi mô bởi vì sự tham gia thực sự là điều cốt lõi trong cơ sở dữ liệu quan hệ. Tôi không có một sự tham gia rất phức tạp ở đây. Điều đầu tiên tôi muốn từ orm là hoàn toàn độc lập phương ngữ vì vậy sql nguyên không phải là một lựa chọn. Thứ hai là có thể (nhưng không bắt buộc) an toàn. Điểm thứ hai chỉ là về quản lý DTO. Nó chỉ là một sự phản đối. Cảm ơn một lần nữa cho một câu trả lời. – ILya

Các vấn đề liên quan