2013-06-26 3 views
6

अगर ServiceStack.OrmLite के JoinSqlBuilder निम्नलिखित सरल प्रश्न के निर्माण की अनुमति मैं सोच रहा हूँ के निर्माण की अनुमति:करता ServiceStack.OrmLite.JoinSqlBuilder एक साधारण क्वेरी

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

समस्या (a.Column2 = 2 OR b.Column3 = 3) हिस्सा निर्माण करना है। JoinSqlBuilder में Where<T>, And<T>, Or<T> जैसी विधियों की एक सूची है जो किसी क्वेरी के लिए शर्तों को जोड़ने की अनुमति देती है।

उदाहरण के लिए

, अगर मैं कार्य करें:

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

मैं मिल जाएगा:

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

वहाँ ServiceStack.OrmLite साथ a.Column1 = 1 AND (a.Column2 = 2 OR b.Column3 = 3) निर्माण करने के लिए कोई तरीका है?

मुझे पता है कि मैं इसे कच्चे एसक्यूएल के साथ कर सकता हूं लेकिन यह एक विकल्प नहीं है क्योंकि मैं टाइप सुरक्षा और बोली स्वतंत्रता खोना नहीं चाहता हूं।

+1

जहां तक ​​मुझे पता है कि यह वहां नहीं है। और सूक्ष्म-ओम इस तरह या चीजों के लिए अच्छा है। आप जटिल परिदृश्यों के लिए सादे पुरानी क्वेरी पर वापस आ सकते हैं। उम्मीद है कि आप क्वेरी () फ़ंक्शन जानते हैं जिसका आप इसका उपयोग कर सकते हैं और यदि आप चाहें तो पैरामीटर पास कर सकते हैं। – kunjee

उत्तर

4

मैं कुंजजी से सहमत हूं कि यह वास्तव में माइक्रो-ओम के लिए अच्छा नहीं है। इसके साथ ही, मैं 2 संभावित विकल्पों के बारे में सोच सकता हूं ... जिनमें से कोई भी वास्तव में कुछ नहीं है, मैं एक समाधान के रूप में एक पूर्ण उड़ा ओआरएम (ईएफ या nHibernate) पर सिफारिश करेंगे। लेकिन, शायद यह बेहतर विकल्प मांगने में मदद करेगा।

विकल्प 1 - कुछ 'प्रकार की सुरक्षा' रखने के लिए प्रतिबिंब का उपयोग करके 'जहां क्लॉज स्ट्रिंग' बनाएं। आपको अभी भी एक छोटा एसक्यूएल लिखना होगा।

उदाहरण

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; 

हेल्पर कक्षा

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

विकल्प 2 - मैस/अपने वर्ग अपवित्र और सही एसक्यूएल होने की अनुमति के लिए एक ExpressionVisitor में टेबल उपसर्ग बंद कर देते हैं उत्पन्न। यदि 2 वर्गों की एक ही संपत्ति है और जहां खंड में उपयोग किया जाता है तो यह पूरी तरह से उड़ाएगा।

//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

एक पूर्ण उत्तर के लिए धन्यवाद। मैं विकल्प 1 के समान smth आ गया है - OrmLite के ExpressionVisitor पर अपना खुद का क्वेरी बिल्डर लिखने के लिए। मैं इस बात से असहमत हूं कि जुड़ना सूक्ष्म ओआरएम के लिए एक कार्य नहीं होना चाहिए क्योंकि संबंध वास्तव में संबंधित डेटाबेस में मुख्य बात है। मेरे पास यहां बहुत जटिल नहीं है। पहली बात जो मैं ओआरएम से चाहता हूं वह पूर्ण बोलीभाषा स्वतंत्रता है इसलिए कच्चा वर्ग एक विकल्प नहीं है। दूसरा एक संभव है (लेकिन आवश्यक नहीं) टाइपफैटी। दूसरा बिंदु डीटीओ के प्रबंधन के बारे में है। यह सिर्फ एक विपक्ष है। एक उत्तर के लिए फिर से धन्यवाद। – ILya

संबंधित मुद्दे