我有这个架构:帖子belongs_to类别和类别has_many帖子。 Post和Category通过gem globalize3进行全球化
class Post < ActiveRecord::Base
belongs_to :category
translates :title, :excerpt, :desc # globalize3
end
class Category < ActiveRecord::Base
has_many :posts
translates :name # globalize3
end
在我的PostsController中,我获得了这行代码的所有帖子:
def index
@posts = Post.includes([:translations, {:category => :translations}])
end
问题是我对类别翻译表有n + 1查询问题:
Post Load (0.3ms) SELECT "posts".* FROM "posts"
Post::Translation Load (0.3ms) SELECT "post_translations".* FROM "post_translations" WHERE ("post_translations".post_id IN (2,3,4))
# START n+1 query block
Category Load (1.9ms) SELECT "categories".* FROM "categories" WHERE ("categories"."id" IN (9,12,11))
Category::Translation Load (0.4ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 9) AND ("category_translations"."locale" IN ('it'))
CACHE (0.0ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 9) AND ("category_translations"."locale" IN ('it'))
Category::Translation Load (0.2ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 12) AND ("category_translations"."locale" IN ('it'))
CACHE (0.0ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 12) AND ("category_translations"."locale" IN ('it'))
Category::Translation Load (0.2ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 11) AND ("category_translations"."locale" IN ('it'))
CACHE (0.0ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id = 11) AND ("category_translations"."locale" IN ('it'))
# END n+1 query block
Category::Translation Load (0.5ms) SELECT "category_translations".* FROM "category_translations" WHERE ("category_translations".category_id IN (9,12,11))
如何解决这个n + 1查询问题?
答案 0 :(得分:11)
您应该在模型中启用预先加载的翻译。建议的方法是:
class Category < ActiveRecord::Base
has_many :posts
translates :name # globalize3
default_scope includes(:translations)
end
答案 1 :(得分:2)
Rails 4 :从MichałSzajbe那里得到答案,这仍然可以稍作修改:
public class MainActivity extends FragmentActivity {
private final String TAG = MainActivity.class.getSimpleName();
List<WeakReference<Fragment>> fragList = new ArrayList<WeakReference<Fragment>>();
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(TAG, "onCreate()");
super.onCreate(savedInstanceState);
setContentView(R.layout.backbone);
android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
android.support.v4.app.Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = new Fragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment, "SystemDownFragment")
.addToBackStack(null)
.commit();
}
}
public void orderFunc() {
Log.d(TAG, "orderFunc()");
if(sendingLogFlag) attemptSend(TAG + ":orderFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment, "OrderFragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
}
public void checkoutFunc() {
Log.d(TAG, "checkoutFunc()");
if(sendingLogFlag) attemptSend(TAG + ":checkoutFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragmentContainer, newFragment, "CheckOutFragment");
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.commit();
}
public void reviewFunc(){
Log.d(TAG, "reviewFunc()");
if(sendingLogFlag) attemptSend(TAG + ":reviewFunc()");
if(getActiveFragments().size() > 1){
Fragment frag = getSupportFragmentManager().findFragmentByTag("ReviewFragment");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.remove(frag);
ft.commit();
}
else {
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "ReviewFragment");
ft.commit();
}
getSupportFragmentManager().executePendingTransactions();
}
public void payFunc(boolean enabled){
Log.d(TAG, "payFunc()");
if(sendingLogFlag) attemptSend(TAG + ":payFunc()");
if(!enabled){
Fragment frag = getSupportFragmentManager().findFragmentByTag("PayFragment");
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE);
ft.remove(frag);
ft.commit();
}
else {
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "PayFragment");
ft.commit();
}
getSupportFragmentManager().executePendingTransactions();
}
public void doneFunc() {
Log.d(TAG, "doneFunc()");
for(int i = 0; i < getActiveFragments().size(); i++) {
getSupportFragmentManager().beginTransaction().remove(getActiveFragments().get(i)).commit();
}
Fragment newFragment = new Fragment();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
ft.add(R.id.fragmentContainer, newFragment, "StartupFragment");
ft.commit();
}
@Override
public void onAttachFragment (Fragment fragment) {
fragList.add(new WeakReference(fragment));
}
public List<Fragment> getActiveFragments() {
ArrayList<Fragment> ret = new ArrayList<Fragment>();
for(WeakReference<Fragment> ref : fragList) {
Fragment f = ref.get();
if(f != null) {
if(f.isVisible()) {
ret.add(f);
}
}
}
return ret;
}
private void updateReceivedData() {
Fragment frag = getSupportFragmentManager().findFragmentByTag("PayFragment");
frag.adjustPriceFunc();
}