2016-03-24 6 views
6

मेरे पास कुछ व्यावसायिक तर्क से निपटने के लिए पोरो (सादा पुरानी रूबी ऑब्जेक्ट) है। इसे ActiveRecord ऑब्जेक्ट प्राप्त होता है और इसे वर्गीकृत करता है। सादगी के लिए, ले एक उदाहरण के रूप में निम्नलिखित:रुबी और एसक्यूएल में डुप्लिकेटेड बिजनेस लॉजिक

class Classificator 
    STATES = { 
     1 => "Positive", 
     2 => "Neutral", 
     3 => "Negative" 
    } 

    def initializer(item) 
     @item = item 
    end 

    def name 
     STATES.fetch(state_id) 
    end 

    private 

    def state_id 
     return 1 if @item.value > 0 
     return 2 if @item.value == 0 
     return 3 if @item.value < 0 
    end 
end 

हालांकि, मैं भी प्रश्नों है कि इन state_id "आभासी विशेषता" के आधार पर समूहों वस्तुओं करना चाहते हैं। मैं वर्तमान में SQL क्वेरी में यह विशेषता बनाकर और GROUP BY कथन में इसका उपयोग करके उस से निपट रहा हूं। उदाहरण देखें:

class Classificator::Query 
    SQL_CONDITIONS = { 
    1 => "items.value > 0", 
    2 => "items.value = 0", 
    3 => "items.value < 0" 
    } 

    def initialize(relation = Item.all) 
    @relation = relation 
    end 

    def count 
    @relation.select(group_conditions).group('state_id').count 
    end 

    private 
    def group_conditions 
    'CASE ' + SQL_CONDITIONS.map do |k, v| 
     'WHEN ' + v.to_s + " THEN " + k.to_s 
    end.join(' ') + " END AS state_id" 
    end 
end 

इस तरह, मैं एसक्यूएल में इस व्यापार तर्क हो और एक बहुत ही कुशल तरीके से क्वेरी इस तरह बना सकते हैं।

समस्या यह है: मेरे पास डुप्लिकेट व्यवसाय तर्क है। यह "रूबी" कोड में मौजूद है, एक ऑब्जेक्ट को वर्गीकृत करने के लिए और डेटाबेस-स्तर में ऑब्जेक्ट्स के संग्रह को वर्गीकृत करने के लिए "SQL" में भी।

क्या यह एक बुरा अभ्यास है? इससे बचने का कोई रास्ता है क्या? मैं वास्तव में यह करने के लिए सक्षम था, निम्नलिखित कर रही:

item = Item.find(4) 
items.select(group_conditions).where(id: item.id).select('state_id') 

लेकिन ऐसा करके, मैं ढीला वस्तुओं है कि डेटाबेस में कायम नहीं कर रहे हैं वर्गीकृत करने की क्षमता। दूसरी तरफ एक इटरेटर का उपयोग करके, प्रत्येक ऑब्जेक्ट को रूबी में वर्गीकृत किया जाएगा, लेकिन फिर मैं डेटाबेस प्रदर्शन खो दूंगा।

यदि मुझे दो मामलों में से सर्वश्रेष्ठ की आवश्यकता है तो डुप्लीकेट व्यवसाय तर्क रखने के लिए यह अपरिहार्य प्रतीत होता है। लेकिन मैं बस इसके बारे में निश्चित होना चाहता हूं। :)

धन्यवाद!

उत्तर

0

क्या डेटाबेस में ट्रिगर पेश करने का कोई मौका है?

def state_if 
    return @item.state_id if @item.state_id # persistent object 

    case @item.value 
    when 0 then 2 
    when -Float::INFINITY...0 then 3 
    else 1 
    end 
end 
+0

यह डेटाबेस में इस क्षेत्र को अद्यतन करके प्रदर्शन में सुधार करेगा। हालांकि, मेरा मानना ​​है कि मेरे पास अभी भी डुप्लीकेट बिजनेस लॉजिक होगा, है ना? डेटाबेस ट्रिगर और 'state_if' विधि दोनों पर। –

+0

@ JoãoDaniel हाँ और नहीं। चाहे व्यापार तर्क लगातार और गैर-लगातार वस्तुओं के लिए समान है, इस दृष्टिकोण के साथ आप सभी तर्क को डीबी परत में डाल सकते हैं और 'start_transaction ⇒ read_state ⇒ रोलबैक' हैक कर सकते हैं। – mudasobwa

0

मैं चाहते हैं: यदि हां, तो मैं "गणना" डेटाबेस में state_id क्षेत्र, कि यह दोनों INSERT और UPDATE पर मूल्य (यह और भी अधिक उत्पादकता लाभ लाएगा) और माणिक में इस कोड में परिवर्तन के साथ जाना होगा बल्कि डेटाबेस को सरल रखें, और जितना संभव हो रूबी कोड में तर्क डालें। चूंकि वर्गीकरण डेटाबेस में संग्रहीत नहीं है, इसलिए मैं क्वेरी को वापस करने की अपेक्षा नहीं करूंगा।

मेरा समाधान एक चिंता को परिभाषित करना है जिसे ActiveRecord मॉडल कक्षाओं में शामिल किया जाएगा।

module Classified 
    extend ActiveSupport::Concern 

    STATES = { 
    1 => "Positive", 
    2 => "Neutral", 
    3 => "Negative" 
    } 

    included do 
    def state_name 
     STATES.fetch(state_id) 
    end 

    private 

    def state_id 
     (0 <=> value.to_i) + 2 
    end 
    end 
end 

class Item < ActiveRecord::Base 
    include Classified 
end 

और मैं सामान्य रूप से डेटाबेस से आइटम लाता हूं।

items = Item.where(...) 

चूंकि प्रत्येक item अपने स्वयं के वर्गीकरण मूल्य जानता है, मैं इसके लिए डेटाबेस पूछने के लिए नहीं है।

items.each do |item| 
    puts item.state_name 
end 
संबंधित मुद्दे