{"id":783,"date":"2025-03-24T08:53:05","date_gmt":"2025-03-23T23:53:05","guid":{"rendered":"https:\/\/dexall.co.jp\/articles\/?p=783"},"modified":"2025-03-24T08:53:05","modified_gmt":"2025-03-23T23:53:05","slug":"%e3%80%90%e4%bf%9d%e5%ae%88%e6%80%a7%e6%8a%9c%e7%be%a4%e3%80%91grails%e3%81%aeselect%e6%96%877%e3%81%a4%e3%81%ae%e5%ae%9f%e8%a3%85%e3%83%91%e3%82%bf%e3%83%bc%e3%83%b3%e3%83%bb%e5%88%9d%e5%bf%83","status":"publish","type":"post","link":"https:\/\/dexall.co.jp\/articles\/?p=783","title":{"rendered":"\u3010\u4fdd\u5b88\u6027\u629c\u7fa4\u3011Grails\u306eselect\u65877\u3064\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u30fb\u521d\u5fc3\u8005\u304b\u3089\u30d7\u30ed\u307e\u3067\u4f7f\u3048\u308b\u5b9f\u8df5\u30ac\u30a4\u30c9"},"content":{"rendered":"\n<div class=\"toc\"><br \/>\n<b>Warning<\/b>:  Undefined array key \"is_admin\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>116<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_category_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>121<\/b><br \/>\n<br \/>\n<b>Warning<\/b>:  Undefined array key \"is_top\" in <b>\/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/sango-theme\/library\/gutenberg\/dist\/classes\/Toc.php<\/b> on line <b>128<\/b><br \/>\n    <div id=\"toc_container\" class=\"sgb-toc--bullets js-smooth-scroll\" data-dialog-title=\"\u76ee\u6b21\">\n      <p class=\"toc_title\">\u76ee\u6b21 <\/p>\n      <ul class=\"toc_list\">  <li class=\"first\">    <a href=\"#i-0\">1. Grails\u3067\u306eselect\u6587\u57fa\u790e\u77e5\u8b58<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-1\">Grails\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a2\u30af\u30bb\u30b9\u6982\u8981<\/a>      <\/li>      <li>        <a href=\"#i-2\">GORM\u3068\u306f\u4f55\u304b\uff1aGrails\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u64cd\u4f5c\u306e\u4e2d\u6838\u6a5f\u80fd<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-3\">select\u6587\u3092\u4f7f\u7528\u3059\u308b\u969b\u306e\u57fa\u672c\u7684\u306a\u8003\u3048\u65b9<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-4\">2. \u57fa\u672c\u7684\u306aselect\u6587\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-5\">findBy\u30e1\u30bd\u30c3\u30c9\u3092\u4f7f\u7528\u3057\u305f\u5358\u7d14\u306a\u691c\u7d22<\/a>      <\/li>      <li>        <a href=\"#i-9\">where\u30af\u30a8\u30ea\u306b\u3088\u308b\u67d4\u8edf\u306a\u691c\u7d22\u6761\u4ef6\u306e\u6307\u5b9a<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-13\">HQL\u3092\u4f7f\u7528\u3057\u305f\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u306e\u5b9f\u88c5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-16\">3. \u9ad8\u5ea6\u306aselect\u6587\u306e\u30c6\u30af\u30cb\u30c3\u30af<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-17\">join\u3092\u4f7f\u7528\u3057\u305f\u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u691c\u7d22<\/a>      <\/li>      <li>        <a href=\"#i-21\">\u52d5\u7684\u306a\u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u306e\u6d3b\u7528\u65b9\u6cd5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-24\">\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u6a5f\u80fd\u306e\u5b9f\u88c5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-27\">4. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8003\u616e\u3057\u305fselect\u6587\u306e\u5b9f\u88c5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-28\">N+1\u554f\u984c\u306e\u56de\u907f\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-32\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u306e\u6700\u9069\u5316<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-35\">\u30ad\u30e3\u30c3\u30b7\u30e5\u6a5f\u80fd\u306e\u52b9\u679c\u7684\u306a\u4f7f\u7528\u6cd5<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-38\">5. \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3092\u8003\u616e\u3057\u305fselect\u6587\u306e\u5b9f\u88c5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-39\">SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-42\">\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306e\u9069\u5207\u306a\u4f7f\u7528<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-45\">\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u306e\u5b9f\u88c5\u30c6\u30af\u30cb\u30c3\u30af<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-48\">6. \u30c6\u30b9\u30c8\u53ef\u80fd\u306aselect\u6587\u306e\u5b9f\u88c5\u65b9\u6cd5<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-49\">\u5358\u4f53\u30c6\u30b9\u30c8\u306e\u4f5c\u6210\u65b9\u6cd5<\/a>      <\/li>      <li>        <a href=\"#i-52\">\u30e2\u30c3\u30af\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\u306e\u5b9f\u88c5<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-54\">\u30c6\u30b9\u30c8\u5bb9\u6613\u6027\u3092\u9ad8\u3081\u308b\u30b3\u30fc\u30c9\u8a2d\u8a08<\/a>      <\/li>    <\/ul>  <\/li>  <li>    <a href=\"#i-56\">7. \u5b9f\u8df5\u7684\u306a\u30e6\u30fc\u30b9\u30b1\u30fc\u30b9\u3068\u5b9f\u88c5\u4f8b<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-57\">\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u3092\u6301\u3064\u753b\u9762\u306e\u5b9f\u88c5\u4f8b<\/a>      <\/li>      <li>        <a href=\"#i-60\">\u5927\u91cf\u30c7\u30fc\u30bf\u51e6\u7406\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-63\">\u30ec\u30ac\u30b7\u30fcDB\u3068\u306e\u9023\u643a\u5b9f\u88c5\u4f8b<\/a>      <\/li>    <\/ul>  <\/li>  <li class=\"last\">    <a href=\"#i-65\">\u307e\u3068\u3081\uff1aGrails\u306eselect\u6587\u5b9f\u88c5\u306b\u304a\u3051\u308b7\u3064\u306e\u91cd\u8981\u30dd\u30a4\u30f3\u30c8<\/a>    <ul class=\"menu_level_1\">      <li class=\"first\">        <a href=\"#i-66\">1. \u57fa\u672c\u8a2d\u8a08\u306e\u91cd\u8981\u6027<\/a>      <\/li>      <li>        <a href=\"#i-67\">2. \u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u306e\u4f7f\u3044\u5206\u3051<\/a>      <\/li>      <li>        <a href=\"#i-68\">3. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u30dd\u30a4\u30f3\u30c8<\/a>      <\/li>      <li>        <a href=\"#i-69\">4. \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5fb9\u5e95<\/a>      <\/li>      <li>        <a href=\"#i-70\">5. \u30c6\u30b9\u30c8\u5bb9\u6613\u6027\u306e\u78ba\u4fdd<\/a>      <\/li>      <li>        <a href=\"#i-71\">6. \u5b9f\u8df5\u7684\u306a\u5b9f\u88c5\u306e\u305f\u3081\u306b<\/a>      <\/li>      <li>        <a href=\"#i-72\">\u4eca\u5f8c\u306e\u767a\u5c55\u306b\u5411\u3051\u3066<\/a>      <\/li>      <li class=\"last\">        <a href=\"#i-73\">\u53c2\u8003\u30ea\u30bd\u30fc\u30b9<\/a>      <\/li>    <\/ul>  <\/li><\/ul>\n      <a href=\"#\" class=\"sgb-toc-button js-toc-button\" rel=\"nofollow\" data-open-dialog=\"true\"><i class=\"fa fa-list\"><\/i><span class=\"sgb-toc-button__text\">\u76ee\u6b21\u3078<\/span><\/a>\n    <\/div><\/div><h2 class=\"wp-block-heading\" id=\"i-0\">1. Grails\u3067\u306eselect\u6587\u57fa\u790e\u77e5\u8b58<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-1\">Grails\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a2\u30af\u30bb\u30b9\u6982\u8981<\/h3>\n\n\n\n<p>Grails\u306f\u3001\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a2\u30af\u30bb\u30b9\u3092\u7c21\u5358\u304b\u3064\u52b9\u7387\u7684\u306b\u884c\u3046\u305f\u3081\u306e\u5f37\u529b\u306a\u6a5f\u80fd\u3092\u63d0\u4f9b\u3057\u3066\u3044\u307e\u3059\u3002\u305d\u306e\u4e2d\u6838\u3068\u306a\u308b\u306e\u304c\u3001GORM\u3068\u547c\u3070\u308c\u308bOR\u30de\u30c3\u30d4\u30f3\u30b0\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-sgb-block-simple sgb-box-simple sgb-box-simple--title-normal sgb-box-simple--with-border\"><div style=\"background-color:var(--wp--preset--color--sango-main);color:#FFF\" class=\"sgb-box-simple__title\">\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a2\u30af\u30bb\u30b9\u306e\u4e3b\u306a\u7279\u5fb4\uff1a<\/div><div class=\"sgb-box-simple__body\" style=\"border-color:var(--wp--preset--color--sango-main);background-color:#FFF\">\n<ul class=\"wp-block-list\">\n<li><strong>\u30c9\u30e1\u30a4\u30f3\u99c6\u52d5\u8a2d\u8a08<\/strong>\uff1a\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30c6\u30fc\u30d6\u30eb\u3092Groovy\u30af\u30e9\u30b9\u3068\u3057\u3066\u8868\u73fe<\/li>\n\n\n\n<li><strong>\u52d5\u7684\u30d5\u30a1\u30a4\u30f3\u30c0\u30fc<\/strong>\uff1a\u30e1\u30bd\u30c3\u30c9\u540d\u3067SQL\u6587\u3092\u81ea\u52d5\u751f\u6210<\/li>\n\n\n\n<li><strong>\u578b\u5b89\u5168\u306a\u30af\u30a8\u30ea<\/strong>\uff1a\u30b3\u30f3\u30d1\u30a4\u30eb\u6642\u306e\u30a8\u30e9\u30fc\u30c1\u30a7\u30c3\u30af\u304c\u53ef\u80fd<\/li>\n\n\n\n<li><strong>\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u7ba1\u7406<\/strong>\uff1a\u81ea\u52d5\u7684\u306a\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u5883\u754c\u306e\u8a2d\u5b9a<\/li>\n<\/ul>\n<\/div><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-2\">GORM\u3068\u306f\u4f55\u304b\uff1aGrails\u306e\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u64cd\u4f5c\u306e\u4e2d\u6838\u6a5f\u80fd<\/h3>\n\n\n\n<p>GORM\uff08Grails Object Relational Mapping\uff09\u306f\u3001Hibernate\u3092\u30d9\u30fc\u30b9\u3068\u3057\u305f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u95a2\u4fc2\u30de\u30c3\u30d4\u30f3\u30b0\uff08ORM\uff09\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u3067\u3059\u3002<\/p>\n\n\n\n<p class=\"is-style-sango-paragraph-idea-alt\">GORM\u306e\u4e3b\u8981\u6a5f\u80fd\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u81ea\u52d5\u30b9\u30ad\u30fc\u30de\u751f\u6210<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9\u306e\u5b9a\u7fa9\u4f8b\nclass Product {\n    String name        \/\/ \u5546\u54c1\u540d\n    BigDecimal price  \/\/ \u4fa1\u683c\n    Date createdAt    \/\/ \u4f5c\u6210\u65e5\n\n    static constraints = {\n        name blank: false\n        price min: 0.0\n    }\n}<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>CRUD\u30e1\u30bd\u30c3\u30c9\u306e\u81ea\u52d5\u751f\u6210<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u4fdd\u5b58\ndef product = new Product(name: \"\u5546\u54c1A\", price: 1000)\nproduct.save()\n\n\/\/ \u691c\u7d22\ndef foundProduct = Product.get(1)  \/\/ ID\u306b\u3088\u308b\u691c\u7d22\n\n\/\/ \u66f4\u65b0\nfoundProduct.price = 1200\nfoundProduct.save()\n\n\/\/ \u524a\u9664\nfoundProduct.delete()<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>\u30ea\u30ec\u30fc\u30b7\u30e7\u30f3\u30b7\u30c3\u30d7\u306e\u7ba1\u7406<\/strong><\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Order {\n    Date orderDate\n    static hasMany = [items: OrderItem]  \/\/ 1\u5bfe\u591a\u306e\u95a2\u4fc2\n}\n\nclass OrderItem {\n    Product product\n    Integer quantity\n    static belongsTo = [order: Order]    \/\/ \u591a\u5bfe1\u306e\u95a2\u4fc2\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-3\">select\u6587\u3092\u4f7f\u7528\u3059\u308b\u969b\u306e\u57fa\u672c\u7684\u306a\u8003\u3048\u65b9<\/h3>\n\n\n\n<p>Grails\u3067select\u6587\u3092\u5b9f\u88c5\u3059\u308b\u969b\u306f\u3001\u4ee5\u4e0b\u306e3\u3064\u306e\u30a2\u30d7\u30ed\u30fc\u30c1\u3092\u72b6\u6cc1\u306b\u5fdc\u3058\u3066\u4f7f\u3044\u5206\u3051\u307e\u3059\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>\u52d5\u7684\u30d5\u30a1\u30a4\u30f3\u30c0\u30fc\u306e\u4f7f\u7528<\/strong>\n<ul class=\"wp-block-list\">\n<li>\u5358\u7d14\u306a\u691c\u7d22\u6761\u4ef6\u306e\u5834\u5408<\/li>\n\n\n\n<li>\u30e1\u30bd\u30c3\u30c9\u540d\u3067\u691c\u7d22\u6761\u4ef6\u3092\u8868\u73fe<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u4fa1\u683c\u304c1000\u5186\u4ee5\u4e0a\u306e\u5546\u54c1\u3092\u691c\u7d22\n   def products = Product.findAllByPriceGreaterThan(1000)<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li><strong>where\u30af\u30a8\u30ea\u306e\u4f7f\u7528<\/strong>\n<ul class=\"wp-block-list\">\n<li>\u8907\u6570\u306e\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u308b\u5834\u5408<\/li>\n\n\n\n<li>\u30af\u30ed\u30fc\u30b8\u30e3\u3067\u691c\u7d22\u6761\u4ef6\u3092\u8868\u73fe<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u7279\u5b9a\u306e\u4fa1\u683c\u7bc4\u56f2\u3068\u540d\u524d\u3067\u691c\u7d22\n   def products = Product.where {\n       price &gt;= 1000 &amp;&amp; price &lt;= 2000 &amp;&amp;\n       name =~ \"\u5546\u54c1%\"  \/\/ \u524d\u65b9\u4e00\u81f4\n   }.list()<\/pre>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\">\n<li><strong>HQL\u306e\u4f7f\u7528<\/strong>\n<ul class=\"wp-block-list\">\n<li>\u8907\u96d1\u306a\u7d50\u5408\u3084\u96c6\u8a08\u304c\u5fc5\u8981\u306a\u5834\u5408<\/li>\n\n\n\n<li>SQL\u98a8\u306e\u6587\u6cd5\u3067\u8a18\u8ff0<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u30ab\u30c6\u30b4\u30ea\u3054\u3068\u306e\u5e73\u5747\u4fa1\u683c\u3092\u8a08\u7b97\n   def results = Product.executeQuery(\"\"\"\n       select p.category.name, avg(p.price)\n       from Product p\n       group by p.category.name\n   \"\"\")<\/pre>\n\n\n\n<p>\u9078\u629e\u306e\u57fa\u6e96\uff1a<\/p>\n\n\n<div id=\"id-9e5f5d50-38c1-4515-934c-d3d99202d393\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u30a2\u30d7\u30ed\u30fc\u30c1<\/th><th>\u4f7f\u7528\u5834\u9762<\/th><th>\u7279\u5fb4<\/th><\/tr><\/thead><tbody><tr><td>\u52d5\u7684\u30d5\u30a1\u30a4\u30f3\u30c0\u30fc<\/td><td>\u5358\u7d14\u306a\u691c\u7d22<\/td><td>\u30fb\u76f4\u611f\u7684\u306a\u8a18\u8ff0<br>\u30fb\u81ea\u52d5\u88dc\u5b8c\u304c\u52b9\u304f<\/td><\/tr><tr><td>where\u30af\u30a8\u30ea<\/td><td>\u8907\u6570\u6761\u4ef6\u306e\u7d44\u307f\u5408\u308f\u305b<\/td><td>\u30fb\u578b\u5b89\u5168<br>\u30fb\u67d4\u8edf\u306a\u6761\u4ef6\u6307\u5b9a<\/td><\/tr><tr><td>HQL<\/td><td>\u8907\u96d1\u306a\u691c\u7d22<\/td><td>\u30fbSQL\u30e9\u30a4\u30af\u306a\u8a18\u8ff0<br>\u30fb\u9ad8\u5ea6\u306a\u5236\u5fa1\u304c\u53ef\u80fd<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u3053\u308c\u3089\u306e\u57fa\u672c\u3092\u62bc\u3055\u3048\u305f\u4e0a\u3067\u3001\u5177\u4f53\u7684\u306a\u30e6\u30fc\u30b9\u30b1\u30fc\u30b9\u306b\u5fdc\u3058\u3066\u6700\u9069\u306a\u30a2\u30d7\u30ed\u30fc\u30c1\u3092\u9078\u629e\u3057\u3066\u3044\u304f\u3053\u3068\u304c\u91cd\u8981\u3067\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-4\">2. \u57fa\u672c\u7684\u306aselect\u6587\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-5\">findBy\u30e1\u30bd\u30c3\u30c9\u3092\u4f7f\u7528\u3057\u305f\u5358\u7d14\u306a\u691c\u7d22<\/h3>\n\n\n\n<p>findBy\u30e1\u30bd\u30c3\u30c9\u306f\u3001Grails\u304c\u63d0\u4f9b\u3059\u308b\u6700\u3082\u30b7\u30f3\u30d7\u30eb\u306a\u691c\u7d22\u65b9\u6cd5\u3067\u3059\u3002\u30e1\u30bd\u30c3\u30c9\u540d\u306b\u691c\u7d22\u6761\u4ef6\u3092\u542b\u3081\u308b\u3053\u3068\u3067\u3001\u76f4\u611f\u7684\u306b\u30af\u30a8\u30ea\u3092\u4f5c\u6210\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-6\">\u57fa\u672c\u7684\u306a\u4f7f\u7528\u65b9\u6cd5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5358\u4e00\u6761\u4ef6\u3067\u306e\u691c\u7d22\ndef user = User.findByEmail(\"test@example.com\")\n\n\/\/ \u8907\u6570\u6761\u4ef6\u3067\u306e\u691c\u7d22\uff08AND\u6761\u4ef6\uff09\ndef product = Product.findByNameAndPrice(\"\u5546\u54c1A\", 1000)\n\n\/\/ Like\u691c\u7d22\ndef users = User.findAllByNameLike(\"\u5c71\u7530%\")\n\n\/\/ \u5927\u5c0f\u6bd4\u8f03\ndef products = Product.findAllByPriceGreaterThan(5000)<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-7\">\u3088\u304f\u4f7f\u7528\u3055\u308c\u308b\u4fee\u98fe\u5b50<\/h4>\n\n\n<div id=\"id-d5ea199c-53b4-4cc2-bd7a-5137bb80262b\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u4fee\u98fe\u5b50<\/th><th>\u8aac\u660e<\/th><th>\u4f7f\u7528\u4f8b<\/th><\/tr><\/thead><tbody><tr><td>LessThan<\/td><td>\u672a\u6e80<\/td><td>findByAgeLessThan(20)<\/td><\/tr><tr><td>GreaterThan<\/td><td>\u3088\u308a\u5927\u304d\u3044<\/td><td>findByPriceGreaterThan(1000)<\/td><\/tr><tr><td>Like<\/td><td>\u90e8\u5206\u4e00\u81f4<\/td><td>findByNameLike(\u201c\u7530\u4e2d%\u201d)<\/td><\/tr><tr><td>Between<\/td><td>\u7bc4\u56f2\u6307\u5b9a<\/td><td>findByPriceBetween(1000, 2000)<\/td><\/tr><tr><td>IsNull<\/td><td>NULL\u5224\u5b9a<\/td><td>findByDeletedAtIsNull()<\/td><\/tr><tr><td>InList<\/td><td>\u30ea\u30b9\u30c8\u5185\u306e\u5024<\/td><td>findAllByStatusInList([\u2018ACTIVE\u2019, \u2018PENDING\u2019])<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<h4 class=\"wp-block-heading\" id=\"i-8\">\u623b\u308a\u5024\u306e\u5236\u5fa1<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5358\u4e00\u30ec\u30b3\u30fc\u30c9\u306e\u53d6\u5f97\ndef user = User.findByEmail(\"test@example.com\")\n\n\/\/ \u8907\u6570\u30ec\u30b3\u30fc\u30c9\u306e\u53d6\u5f97\ndef users = User.findAllByAgeGreaterThan(20)\n\n\/\/ \u30bd\u30fc\u30c8\u6307\u5b9a\ndef products = Product.findAllByPriceGreaterThan(1000, [sort: 'name', order: 'desc'])\n\n\/\/ \u53d6\u5f97\u4ef6\u6570\u306e\u5236\u9650\ndef recentUsers = User.findAllByActive(true, [max: 10, offset: 0])<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-9\">where\u30af\u30a8\u30ea\u306b\u3088\u308b\u67d4\u8edf\u306a\u691c\u7d22\u6761\u4ef6\u306e\u6307\u5b9a<\/h3>\n\n\n\n<p>where\u30af\u30a8\u30ea\u306f\u3001\u3088\u308a\u8907\u96d1\u306a\u6761\u4ef6\u3092\u578b\u5b89\u5168\u306b\u8a18\u8ff0\u3067\u304d\u308b\u65b9\u6cd5\u3067\u3059\u3002\u30af\u30ed\u30fc\u30b8\u30e3\u3092\u4f7f\u7528\u3057\u3066\u6761\u4ef6\u3092\u6307\u5b9a\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-10\">\u57fa\u672c\u7684\u306a\u4f7f\u7528\u65b9\u6cd5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5358\u7d14\u306a\u6761\u4ef6\u6307\u5b9a\ndef products = Product.where {\n    price &gt;= 1000 &amp;&amp; price &lt;= 2000\n}.list()\n\n\/\/ OR\u6761\u4ef6\u306e\u6307\u5b9a\ndef users = User.where {\n    age &gt;= 20 || status == 'VIP'\n}.list()\n\n\/\/ \u30cd\u30b9\u30c8\u3057\u305f\u6761\u4ef6\ndef orders = Order.where {\n    (status == 'PENDING' &amp;&amp; amount &gt; 10000) ||\n    (status == 'APPROVED' &amp;&amp; amount &gt; 5000)\n}.list()<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-11\">\u52d5\u7684\u6761\u4ef6\u306e\u69cb\u7bc9<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def searchProducts(Map params) {\n    def criteria = Product.where {\n        if (params.minPrice) {\n            price &gt;= params.minPrice\n        }\n        if (params.maxPrice) {\n            price &lt;= params.maxPrice\n        }\n        if (params.category) {\n            category == params.category\n        }\n    }\n    return criteria.list()\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-12\">\u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u6761\u4ef6\u6307\u5b9a<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u6761\u4ef6\u3092\u542b\u3081\u308b\ndef orders = Order.where {\n    customer.city == 'Tokyo' &amp;&amp;\n    items.any { item -&gt;\n        item.product.category == 'Electronics'\n    }\n}.list()<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-13\">HQL\u3092\u4f7f\u7528\u3057\u305f\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>HQL\uff08Hibernate Query Language\uff09\u306f\u3001\u3088\u308a\u8907\u96d1\u306a\u30af\u30a8\u30ea\u3084\u7279\u6b8a\u306a\u691c\u7d22\u6761\u4ef6\u3092\u5b9f\u88c5\u3059\u308b\u969b\u306b\u4f7f\u7528\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-14\">\u57fa\u672c\u7684\u306a\u4f7f\u7528\u65b9\u6cd5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5358\u7d14\u306aSELECT\ndef users = User.executeQuery(\"\"\"\n    FROM User u\n    WHERE u.age &gt; :age\n    ORDER BY u.name\n\"\"\", [age: 20])\n\n\/\/ \u96c6\u8a08\u95a2\u6570\u306e\u4f7f\u7528\ndef results = Order.executeQuery(\"\"\"\n    SELECT o.status, COUNT(o), SUM(o.amount)\n    FROM Order o\n    GROUP BY o.status\n\"\"\")\n\n\/\/ JOIN\u53e5\u306e\u4f7f\u7528\ndef orders = Order.executeQuery(\"\"\"\n    SELECT o, c\n    FROM Order o\n    JOIN o.customer c\n    WHERE c.city = :city\n    AND o.amount &gt; :amount\n\"\"\", [city: 'Tokyo', amount: 10000])<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-15\">\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u540d\u524d\u4ed8\u304d\u30d1\u30e9\u30e1\u30fc\u30bf\ndef products = Product.executeQuery(\"\"\"\n    FROM Product p\n    WHERE p.price BETWEEN :minPrice AND :maxPrice\n    AND p.category = :category\n\"\"\", [minPrice: 1000, maxPrice: 2000, category: 'Electronics'])\n\n\/\/ \u30ea\u30b9\u30c8\u30d1\u30e9\u30e1\u30fc\u30bf\ndef users = User.executeQuery(\"\"\"\n    FROM User u\n    WHERE u.status IN (:statusList)\n\"\"\", [statusList: ['ACTIVE', 'PENDING']])<\/pre>\n\n\n\n<p>\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u306e\u9078\u629e\u6307\u91dd\uff1a<\/p>\n\n\n<div id=\"id-f7262d79-d1bb-42e5-86d3-c51bf73dd4d8\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u30d1\u30bf\u30fc\u30f3<\/th><th>\u9069\u3057\u3066\u3044\u308b\u5834\u9762<\/th><th>\u6ce8\u610f\u70b9<\/th><\/tr><\/thead><tbody><tr><td>findBy<\/td><td>\u5358\u7d14\u306a\u691c\u7d22\u6761\u4ef6<\/td><td>\u6761\u4ef6\u304c\u8907\u96d1\u306b\u306a\u308b\u3068\u53ef\u8aad\u6027\u304c\u4f4e\u4e0b<\/td><\/tr><tr><td>where<\/td><td>\u52d5\u7684\u306a\u691c\u7d22\u6761\u4ef6<\/td><td>\u8907\u96d1\u306a\u96c6\u8a08\u306b\u306f\u4e0d\u5411\u304d<\/td><\/tr><tr><td>HQL<\/td><td>\u8907\u96d1\u306a\u691c\u7d22\u30fb\u96c6\u8a08<\/td><td>SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u306b\u6ce8\u610f<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u3053\u308c\u3089\u306e\u30d1\u30bf\u30fc\u30f3\u3092\u72b6\u6cc1\u306b\u5fdc\u3058\u3066\u9069\u5207\u306b\u4f7f\u3044\u5206\u3051\u308b\u3053\u3068\u3067\u3001\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u5b9f\u88c5\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-16\">3. \u9ad8\u5ea6\u306aselect\u6587\u306e\u30c6\u30af\u30cb\u30c3\u30af<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-17\">join\u3092\u4f7f\u7528\u3057\u305f\u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u691c\u7d22<\/h3>\n\n\n\n<p>\u8907\u6570\u306e\u30c6\u30fc\u30d6\u30eb\u3092\u7d50\u5408\u3057\u3066\u691c\u7d22\u3059\u308b\u5834\u5408\u3001\u9069\u5207\u306ajoin\u6226\u7565\u306e\u9078\u629e\u304c\u91cd\u8981\u3067\u3059\u3002Grails\u3067\u306f\u3001\u8907\u6570\u306e\u65b9\u6cd5\u3067join\u3092\u5b9f\u88c5\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-18\">\u6697\u9ed9\u7684\u306ajoin<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9\u306e\u5b9a\u7fa9\nclass Order {\n    Date orderDate\n    static hasMany = [items: OrderItem]\n    static belongsTo = [customer: Customer]\n}\n\n\/\/ \u95a2\u9023\u30c6\u30fc\u30d6\u30eb\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306b\u76f4\u63a5\u30a2\u30af\u30bb\u30b9\ndef orders = Order.where {\n    customer.city == 'Tokyo' &amp;&amp;\n    items.any { item -&gt;\n        item.product.category == 'Electronics'\n    }\n}.list()<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-19\">\u660e\u793a\u7684\u306ajoin\uff08HQL\u3092\u4f7f\u7528\uff09<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ INNER JOIN\u306e\u4f8b\ndef results = Order.executeQuery(\"\"\"\n    SELECT DISTINCT o, c\n    FROM Order o\n    INNER JOIN o.customer c\n    INNER JOIN o.items i\n    WHERE c.city = :city\n    AND i.product.category = :category\n\"\"\", [city: 'Tokyo', category: 'Electronics'])\n\n\/\/ LEFT OUTER JOIN\u306e\u4f8b\ndef results = Order.executeQuery(\"\"\"\n    SELECT o, c\n    FROM Order o\n    LEFT OUTER JOIN o.customer c\n    WHERE o.amount &gt; :amount\n\"\"\", [amount: 10000])<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-20\">join\u6226\u7565\u306e\u6700\u9069\u5316<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30d5\u30a7\u30c3\u30c1\u6226\u7565\u306e\u6307\u5b9a\ndef orders = Order.where {\n    customer.city == 'Tokyo'\n}.join('customer')  \/\/ \u5373\u6642\u30ed\u30fc\u30c9\n .join('items', JoinType.LEFT)  \/\/ \u5de6\u5916\u90e8\u7d50\u5408\n .list()\n\n\/\/ \u30af\u30a8\u30ea\u306e\u30c1\u30e5\u30fc\u30cb\u30f3\u30b0\u4f8b\ndef results = Order.createCriteria().list {\n    createAlias('customer', 'c')\n    createAlias('items', 'i', CriteriaSpecification.LEFT_JOIN)\n    eq('c.city', 'Tokyo')\n    gt('amount', 10000)\n    projections {\n        distinct(['id', 'orderDate'])\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-21\">\u52d5\u7684\u306a\u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u306e\u6d3b\u7528\u65b9\u6cd5<\/h3>\n\n\n\n<p>\u691c\u7d22\u6761\u4ef6\u304c\u5b9f\u884c\u6642\u306b\u6c7a\u5b9a\u3055\u308c\u308b\u5834\u5408\u3001\u52d5\u7684\u306a\u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u3092\u4f7f\u7528\u3059\u308b\u3068\u67d4\u8edf\u306a\u5b9f\u88c5\u304c\u53ef\u80fd\u3067\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-22\">\u57fa\u672c\u7684\u306a\u52d5\u7684\u30af\u30a8\u30ea<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ProductService {\n    List&lt;Product&gt; searchProducts(Map params) {\n        def criteria = Product.createCriteria()\n        def results = criteria.list {\n            if (params.category) {\n                eq('category', params.category)\n            }\n            if (params.minPrice) {\n                ge('price', params.minPrice as BigDecimal)\n            }\n            if (params.maxPrice) {\n                le('price', params.maxPrice as BigDecimal)\n            }\n            if (params.keywords) {\n                or {\n                    ilike('name', \"%${params.keywords}%\")\n                    ilike('description', \"%${params.keywords}%\")\n                }\n            }\n            order(params.sort ?: 'name', params.order ?: 'asc')\n            maxResults(params.max ?: 10)\n            firstResult(params.offset ?: 0)\n        }\n        return results\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-23\">\u9ad8\u5ea6\u306a\u52d5\u7684\u30af\u30a8\u30ea<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class OrderService {\n    def complexSearch(Map params) {\n        def criteria = Order.createCriteria()\n\n        return criteria.list {\n            createAlias('customer', 'c')\n            createAlias('items', 'i')\n            createAlias('i.product', 'p')\n\n            \/\/ \u57fa\u672c\u6761\u4ef6\n            if (params.dateFrom) {\n                ge('orderDate', params.dateFrom)\n            }\n            if (params.dateTo) {\n                le('orderDate', params.dateTo)\n            }\n\n            \/\/ \u30cd\u30b9\u30c8\u3057\u305f\u6761\u4ef6\n            if (params.customerTypes) {\n                'c' {\n                    'in'('type', params.customerTypes)\n                }\n            }\n\n            \/\/ \u30b5\u30d6\u30af\u30a8\u30ea\n            if (params.minItemCount) {\n                sqlRestriction \"\"\"\n                    {alias}.id IN (\n                        SELECT o.id \n                        FROM orders o \n                        JOIN order_items oi ON o.id = oi.order_id \n                        GROUP BY o.id \n                        HAVING COUNT(*) &gt;= :minCount\n                    )\n                \"\"\", [minCount: params.minItemCount]\n            }\n\n            \/\/ \u96c6\u8a08\u6761\u4ef6\n            projections {\n                groupProperty('id')\n                sum('amount', 'totalAmount')\n                count('i.id', 'itemCount')\n            }\n\n            \/\/ \u30bd\u30fc\u30c8\u3068\u30da\u30fc\u30b8\u30f3\u30b0\n            order(params.sort ?: 'orderDate', params.order ?: 'desc')\n            maxResults(params.max ?: 20)\n            firstResult(params.offset ?: 0)\n        }\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-24\">\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u6a5f\u80fd\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>\u5927\u91cf\u306e\u30c7\u30fc\u30bf\u3092\u6271\u3046\u5834\u5408\u3001\u52b9\u7387\u7684\u306a\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u306e\u5b9f\u88c5\u304c\u91cd\u8981\u3067\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-25\">\u57fa\u672c\u7684\u306a\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ProductController {\n    def index(Integer max, Integer offset) {\n        params.max = Math.min(max ?: 10, 100)\n        params.offset = offset ?: 0\n\n        def criteria = Product.createCriteria()\n        def results = criteria.list(params) {\n            if (params.category) {\n                eq('category', params.category)\n            }\n            order('name', 'asc')\n        }\n\n        [\n            productList: results,\n            productCount: Product.count(),\n            params: params\n        ]\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-26\">\u9ad8\u5ea6\u306a\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class SearchService {\n    def pagedSearch(Map params) {\n        def pageSize = Math.min(params.max ?: 10, 100)\n        def currentPage = (params.offset ?: 0) \/ pageSize + 1\n\n        def criteria = Product.createCriteria()\n        def results = criteria.list {\n            resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)\n\n            createAlias('category', 'c')\n\n            \/\/ \u691c\u7d22\u6761\u4ef6\n            if (params.keyword) {\n                or {\n                    ilike('name', \"%${params.keyword}%\")\n                    ilike('description', \"%${params.keyword}%\")\n                }\n            }\n\n            \/\/ Eager Loading\n            fetchMode('category', FetchMode.JOIN)\n            fetchMode('tags', FetchMode.JOIN)\n\n            \/\/ \u30da\u30fc\u30b8\u30f3\u30b0\n            maxResults(pageSize)\n            firstResult(params.offset ?: 0)\n\n            \/\/ \u30ab\u30a6\u30f3\u30c8\u30af\u30a8\u30ea\u306e\u6700\u9069\u5316\n            projections {\n                distinct(['id', 'name', 'price'])\n                property('c.name', 'categoryName')\n            }\n        }\n\n        \/\/ \u7dcf\u4ef6\u6570\u306e\u53d6\u5f97\uff08\u5225\u30af\u30a8\u30ea\u3067\u52b9\u7387\u5316\uff09\n        def totalCount = Product.createCriteria().get {\n            projections {\n                countDistinct('id')\n            }\n            \/\/ \u540c\u3058\u691c\u7d22\u6761\u4ef6\u3092\u9069\u7528\n            if (params.keyword) {\n                or {\n                    ilike('name', \"%${params.keyword}%\")\n                    ilike('description', \"%${params.keyword}%\")\n                }\n            }\n        }\n\n        [\n            results: results,\n            total: totalCount,\n            currentPage: currentPage,\n            pageCount: Math.ceil(totalCount \/ pageSize)\n        ]\n    }\n}<\/pre>\n\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u5b9f\u88c5\u306e\u30dd\u30a4\u30f3\u30c8\uff1a<\/p>\n\n\n<div id=\"id-96cfbc19-fad3-4194-9b71-367e9e5af524\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u6a5f\u80fd<\/th><th>\u91cd\u8981\u306a\u8003\u616e\u70b9<\/th><th>\u63a8\u5968\u3055\u308c\u308b\u5b9f\u88c5\u65b9\u6cd5<\/th><\/tr><\/thead><tbody><tr><td>Join<\/td><td>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316<\/td><td>\u5fc5\u8981\u306a\u7d50\u5408\u306e\u307f\u3092\u4f7f\u7528\u3001Eager\/Lazy Loading\u306e\u9069\u5207\u306a\u9078\u629e<\/td><\/tr><tr><td>\u52d5\u7684\u30af\u30a8\u30ea<\/td><td>\u4fdd\u5b88\u6027\u3068\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3<\/td><td>\u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u306e\u4f7f\u7528\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u30d0\u30a4\u30f3\u30c9<\/td><\/tr><tr><td>\u30da\u30fc\u30b8\u30cd\u30fc\u30b7\u30e7\u30f3<\/td><td>\u30b9\u30b1\u30fc\u30e9\u30d3\u30ea\u30c6\u30a3<\/td><td>\u9069\u5207\u306a\u30da\u30fc\u30b8\u30b5\u30a4\u30ba\u3001\u52b9\u7387\u7684\u306a\u30ab\u30a6\u30f3\u30c8\u30af\u30a8\u30ea<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u3053\u308c\u3089\u306e\u9ad8\u5ea6\u306a\u30c6\u30af\u30cb\u30c3\u30af\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3068\u4fdd\u5b88\u6027\u3092\u4e21\u7acb\u3057\u305f\u5b9f\u88c5\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-27\">4. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u8003\u616e\u3057\u305fselect\u6587\u306e\u5b9f\u88c5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-28\">N+1\u554f\u984c\u306e\u56de\u907f\u65b9\u6cd5<\/h3>\n\n\n\n<p>N+1\u554f\u984c\u306f\u3001ORM\u3092\u4f7f\u7528\u3059\u308b\u969b\u306b\u3088\u304f\u767a\u751f\u3059\u308b\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u554f\u984c\u3067\u3059\u3002\u89aa\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u3092\u53d6\u5f97\u3057\u305f\u5f8c\u3001\u95a2\u9023\u3059\u308b\u5b50\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u3092\u500b\u5225\u306b\u53d6\u5f97\u3059\u308b\u3053\u3068\u3067\u3001\u5927\u91cf\u306eSQL\u30af\u30a8\u30ea\u304c\u767a\u884c\u3055\u308c\u308b\u73fe\u8c61\u3092\u6307\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-29\">N+1\u554f\u984c\u306e\u4f8b<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ N+1\u554f\u984c\u304c\u767a\u751f\u3059\u308b\u30b3\u30fc\u30c9\ndef orders = Order.list()  \/\/ 1\u56de\u76ee\u306e\u30af\u30a8\u30ea\norders.each { order -&gt;\n    order.items.each { item -&gt;  \/\/ N\u56de\u306e\u30af\u30a8\u30ea\n        println item.product.name\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-30\">\u89e3\u6c7a\u65b9\u6cd51: join\u3092\u4f7f\u7528\u3057\u305f\u5373\u6642\u30ed\u30fc\u30c9<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ createCriteria\u3092\u4f7f\u7528\u3057\u305f\u89e3\u6c7a\u7b56\ndef orders = Order.createCriteria().list {\n    fetchMode 'items', FetchMode.JOIN\n    fetchMode 'items.product', FetchMode.JOIN\n    resultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)\n}\n\n\/\/ HQL\u3092\u4f7f\u7528\u3057\u305f\u89e3\u6c7a\u7b56\ndef orders = Order.executeQuery(\"\"\"\n    SELECT DISTINCT o FROM Order o\n    LEFT JOIN FETCH o.items i\n    LEFT JOIN FETCH i.product\n\"\"\")<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-31\">\u89e3\u6c7a\u65b9\u6cd52: \u30d0\u30c3\u30c1\u53d6\u5f97\u306e\u8a2d\u5b9a<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9\u3067\u306e\u30d0\u30c3\u30c1\u30b5\u30a4\u30ba\u8a2d\u5b9a\nclass Order {\n    static hasMany = [items: OrderItem]\n\n    static mapping = {\n        items batchSize: 25  \/\/ \u30d0\u30c3\u30c1\u30b5\u30a4\u30ba\u306e\u6307\u5b9a\n    }\n}\n\n\/\/ \u30d0\u30c3\u30c1\u53d6\u5f97\u3092\u4f7f\u7528\u3057\u305f\u5b9f\u88c5\ndef orders = Order.createCriteria().list {\n    maxResults(100)\n    fetchMode 'items', FetchMode.SELECT\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-32\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u6d3b\u7528\u3057\u305f\u691c\u7d22\u306e\u6700\u9069\u5316<\/h3>\n\n\n\n<p>\u9069\u5207\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8a2d\u5b9a\u306f\u3001\u691c\u7d22\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u5927\u304d\u304f\u5411\u4e0a\u3055\u305b\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-33\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8a2d\u5b9a\u306e\u4f8b<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9\u3067\u306e\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u5b9a\u7fa9\nclass Product {\n    String name\n    String category\n    BigDecimal price\n    Date createdAt\n\n    static mapping = {\n        \/\/ \u5358\u4e00\u30ab\u30e9\u30e0\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\n        name index: 'idx_product_name'\n\n        \/\/ \u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\n        category column: 'category', index: 'idx_product_cat_price'\n        price column: 'price', index: 'idx_product_cat_price'\n\n        \/\/ \u30e6\u30cb\u30fc\u30af\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\n        barcode index: 'idx_product_barcode', unique: true\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-34\">\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u6d3b\u7528\u3057\u305f\u30af\u30a8\u30ea<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u52b9\u679c\u7684\u306b\u4f7f\u7528\u3059\u308b\u30af\u30a8\u30ea\ndef searchProducts(String category, BigDecimal minPrice) {\n    Product.createCriteria().list {\n        eq('category', category)  \/\/ \u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u5148\u982d\u30ab\u30e9\u30e0\n        ge('price', minPrice)     \/\/ \u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e2\u756a\u76ee\u306e\u30ab\u30e9\u30e0\n        order('price', 'asc')     \/\/ \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3092\u4f7f\u7528\u3057\u305f\u30bd\u30fc\u30c8\n    }\n}\n\n\/\/ \u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u30d2\u30f3\u30c8\u306e\u4f7f\u7528\uff08HQL\uff09\ndef products = Product.executeQuery(\"\"\"\n    FROM Product p USE INDEX (idx_product_cat_price)\n    WHERE p.category = :category\n    AND p.price &gt;= :minPrice\n\"\"\", [category: 'Electronics', minPrice: 1000])<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-35\">\u30ad\u30e3\u30c3\u30b7\u30e5\u6a5f\u80fd\u306e\u52b9\u679c\u7684\u306a\u4f7f\u7528\u6cd5<\/h3>\n\n\n\n<p>Grails\u306f\u8907\u6570\u30ec\u30d9\u30eb\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u63d0\u4f9b\u3057\u3066\u304a\u308a\u3001\u9069\u5207\u306b\u4f7f\u7528\u3059\u308b\u3053\u3068\u3067\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-36\">2\u6b21\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u8a2d\u5b9a<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u8a2d\u5b9a\uff08application.yml\uff09\nhibernate:\n    cache:\n        use_second_level_cache: true\n        use_query_cache: true\n        region:\n            factory_class: 'org.hibernate.cache.ehcache.EhCacheRegionFactory'\n\n\/\/ \u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9\u3067\u306e\u30ad\u30e3\u30c3\u30b7\u30e5\u8a2d\u5b9a\nclass Product {\n    static mapping = {\n        cache usage: 'read-write', include: 'non-lazy'\n    }\n\n    static constraints = {\n        \/\/ ...\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-37\">\u30ad\u30e3\u30c3\u30b7\u30e5\u3092\u6d3b\u7528\u3057\u305f\u30af\u30a8\u30ea\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ProductService {\n    static transactional = false\n\n    \/\/ \u30af\u30a8\u30ea\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u4f7f\u7528\n    List&lt;Product&gt; findPopularProducts() {\n        Product.createCriteria().list {\n            cache true  \/\/ \u30af\u30a8\u30ea\u7d50\u679c\u3092\u30ad\u30e3\u30c3\u30b7\u30e5\n            gt('rating', 4.0)\n            order('rating', 'desc')\n            maxResults(10)\n        }\n    }\n\n    \/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u5236\u5fa1\n    void updateProduct(Product product) {\n        product.save(flush: true)\n        \/\/ \u95a2\u9023\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u660e\u793a\u7684\u306a\u524a\u9664\n        Product.withSession { session -&gt;\n            session.cache.evictQuery('Product.findPopularProducts')\n        }\n    }\n}<\/pre>\n\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\uff1a<\/p>\n\n\n<div id=\"id-6c62680d-a77d-4126-bc47-93c7366747b2\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u554f\u984c\u70b9<\/th><th>\u78ba\u8a8d\u9805\u76ee<\/th><th>\u5bfe\u5fdc\u65b9\u6cd5<\/th><\/tr><\/thead><tbody><tr><td>N+1\u554f\u984c<\/td><td>\u30fb\u95a2\u9023\u30a8\u30f3\u30c6\u30a3\u30c6\u30a3\u306e\u53d6\u5f97\u65b9\u6cd5<br>\u30fbSQL\u767a\u884c\u56de\u6570<\/td><td>\u30fb\u9069\u5207\u306a\u30d5\u30a7\u30c3\u30c1\u6226\u7565\u306e\u9078\u629e<br>\u30fb\u30d0\u30c3\u30c1\u30b5\u30a4\u30ba\u306e\u8a2d\u5b9a<\/td><\/tr><tr><td>\u30a4\u30f3\u30c7\u30c3\u30af\u30b9<\/td><td>\u30fb\u691c\u7d22\u6761\u4ef6\u306e\u5206\u6790<br>\u30fb\u5b9f\u884c\u8a08\u753b\u306e\u78ba\u8a8d<\/td><td>\u30fb\u9069\u5207\u306a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8a2d\u5b9a<br>\u30fb\u8907\u5408\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u6d3b\u7528<\/td><\/tr><tr><td>\u30ad\u30e3\u30c3\u30b7\u30e5<\/td><td>\u30fb\u30c7\u30fc\u30bf\u306e\u66f4\u65b0\u983b\u5ea6<br>\u30fb\u30e1\u30e2\u30ea\u4f7f\u7528\u91cf<\/td><td>\u30fb\u30ad\u30e3\u30c3\u30b7\u30e5\u6226\u7565\u306e\u9078\u629e<br>\u30fb\u30ad\u30e3\u30c3\u30b7\u30e5\u306e\u6709\u52b9\u671f\u9650\u8a2d\u5b9a<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u76e3\u8996\u306e\u30dd\u30a4\u30f3\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>SQL\u30ed\u30b0\u306e\u76e3\u8996<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   # application.yml\n   hibernate:\n       show_sql: true\n       format_sql: true\n       use_sql_comments: true<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>\u5b9f\u884c\u6642\u9593\u306e\u8a08\u6e2c<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   def measureQueryTime(Closure query) {\n       def startTime = System.currentTimeMillis()\n       def result = query.call()\n       def endTime = System.currentTimeMillis()\n       log.info \"Query execution time: ${endTime - startTime}ms\"\n       return result\n   }<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u6700\u9069\u5316\u30c6\u30af\u30cb\u30c3\u30af\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u5fdc\u7b54\u6027\u3068\u30b9\u30b1\u30fc\u30e9\u30d3\u30ea\u30c6\u30a3\u3092\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-38\">5. \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3092\u8003\u616e\u3057\u305fselect\u6587\u306e\u5b9f\u88c5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-39\">SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h3>\n\n\n\n<p>SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u306f\u3001\u6700\u3082\u6df1\u523b\u306a\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u8106\u5f31\u6027\u306e\u4e00\u3064\u3067\u3059\u3002Grails\u306f\u6a19\u6e96\u3067SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56\u6a5f\u80fd\u3092\u63d0\u4f9b\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u9069\u5207\u306b\u4f7f\u7528\u3059\u308b\u5fc5\u8981\u304c\u3042\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-40\">\u8106\u5f31\u306a\u5b9f\u88c5\u4f8b\u3068\u5b89\u5168\u306a\u5b9f\u88c5\u4f8b<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u5371\u967a\u306a\u5b9f\u88c5\u4f8b\uff08\u7d76\u5bfe\u306b\u4f7f\u7528\u3057\u306a\u3044\u3067\u304f\u3060\u3055\u3044\uff09\ndef findUsersByName(String name) {\n    def sql = new Sql(dataSource)\n    def query = \"SELECT * FROM user WHERE name LIKE '${name}%'\"  \/\/ \u5371\u967a\uff01\n    return sql.rows(query)\n}\n\n\/\/ \u5b89\u5168\u306a\u5b9f\u88c5\u4f8b1\uff1aGORM\u306e\u4f7f\u7528\ndef findUsersByName(String name) {\n    User.findAllByNameLike(name + '%')  \/\/ \u81ea\u52d5\u7684\u306b\u30a8\u30b9\u30b1\u30fc\u30d7\u3055\u308c\u308b\n}\n\n\/\/ \u5b89\u5168\u306a\u5b9f\u88c5\u4f8b2\uff1a\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\ndef findUsersByCustomQuery(String name) {\n    User.executeQuery(\"\"\"\n        FROM User u\n        WHERE u.name LIKE :namePattern\n    \"\"\", [namePattern: name + '%'])\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-41\">\u52d5\u7684\u30af\u30a8\u30ea\u3067\u306e\u5b89\u5168\u306a\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class SearchService {\n    def searchProducts(Map params) {\n        def criteria = Product.createCriteria()\n        return criteria.list {\n            \/\/ \u5b89\u5168\u306a\u52d5\u7684\u6761\u4ef6\u306e\u69cb\u7bc9\n            if (params.category) {\n                eq('category', params.category)  \/\/ \u81ea\u52d5\u7684\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u308b\n            }\n\n            if (params.keywords) {\n                or {\n                    \/\/ \u30ef\u30a4\u30eb\u30c9\u30ab\u30fc\u30c9\u306f\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u4e00\u90e8\u3068\u3057\u3066\u6e21\u3059\n                    ilike('name', \"%${params.keywords.replaceAll(\/[%_]\/, '')}%\")\n                    ilike('description', \"%${params.keywords.replaceAll(\/[%_]\/, '')}%\")\n                }\n            }\n\n            \/\/ \u5b89\u5168\u306a\u30bd\u30fc\u30c8\u5b9f\u88c5\n            if (params.sort &amp;&amp; params.sort in ['name', 'price', 'category']) {\n                order(params.sort, params.order ?: 'asc')\n            }\n        }\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-42\">\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306e\u9069\u5207\u306a\u4f7f\u7528<\/h3>\n\n\n\n<p>\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306f\u3001SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56\u306e\u57fa\u672c\u3067\u3059\u3002Grails\u3067\u306f\u8907\u6570\u306e\u65b9\u6cd5\u3067\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u3092\u5b9f\u88c5\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-43\">\u540d\u524d\u4ed8\u304d\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u4f7f\u7528<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class OrderService {\n    def findOrders(Date startDate, Date endDate, List&lt;String&gt; statuses) {\n        Order.executeQuery(\"\"\"\n            FROM Order o\n            WHERE o.orderDate BETWEEN :startDate AND :endDate\n            AND o.status IN (:statuses)\n        \"\"\", [\n            startDate: startDate,\n            endDate: endDate,\n            statuses: statuses\n        ])\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-44\">\u52d5\u7684\u6761\u4ef6\u3067\u306e\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ProductService {\n    def searchWithSafeBinding(Map params) {\n        def conditions = []\n        def parameters = [:]\n\n        if (params.minPrice) {\n            conditions &lt;&lt; \"p.price &gt;= :minPrice\"\n            parameters.minPrice = params.minPrice as BigDecimal\n        }\n\n        if (params.category) {\n            conditions &lt;&lt; \"p.category = :category\"\n            parameters.category = params.category\n        }\n\n        def whereClause = conditions ? \"WHERE \" + conditions.join(\" AND \") : \"\"\n\n        Product.executeQuery(\"\"\"\n            FROM Product p\n            ${whereClause}\n            ORDER BY p.name\n        \"\"\", parameters)\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-45\">\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u306e\u5b9f\u88c5\u30c6\u30af\u30cb\u30c3\u30af<\/h3>\n\n\n\n<p>\u30c7\u30fc\u30bf\u3078\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u306f\u3001\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u91cd\u8981\u306a\u8981\u7d20\u3067\u3059\u3002Grails\u3067\u306f\u3001\u8907\u6570\u30ec\u30d9\u30eb\u3067\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u3092\u5b9f\u88c5\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-46\">\u30c9\u30e1\u30a4\u30f3\u30ec\u30d9\u30eb\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class Document {\n    String title\n    String content\n    User owner\n\n    static constraints = {\n        title blank: false\n        content blank: false\n        owner nullable: false\n    }\n\n    \/\/ \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u30e1\u30bd\u30c3\u30c9\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\n    boolean canAccess(User user) {\n        return owner == user || user.hasRole('ADMIN')\n    }\n\n    \/\/ \u9759\u7684\u30e1\u30bd\u30c3\u30c9\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\n    static List&lt;Document&gt; findAccessibleDocuments(User currentUser) {\n        if (currentUser.hasRole('ADMIN')) {\n            return Document.list()\n        }\n\n        Document.where {\n            owner == currentUser\n        }.list()\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-47\">\u30b5\u30fc\u30d3\u30b9\u30ec\u30d9\u30eb\u3067\u306e\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">@Secured(['ROLE_USER'])\nclass DocumentService {\n    def springSecurityService\n\n    @Secured(['ROLE_ADMIN'])\n    List&lt;Document&gt; findAll() {\n        Document.list()\n    }\n\n    Document findById(Long id) {\n        def currentUser = springSecurityService.currentUser as User\n        def document = Document.get(id)\n\n        if (!document || !document.canAccess(currentUser)) {\n            throw new AccessDeniedException(\"Access denied to document: ${id}\")\n        }\n\n        return document\n    }\n\n    @PreAuthorize(\"hasRole('ROLE_ADMIN') or #document.owner.id == authentication.principal.id\")\n    void update(Document document, Map params) {\n        document.properties = params\n        document.save(flush: true)\n    }\n}<\/pre>\n\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\uff1a<\/p>\n\n\n<div id=\"id-72726ed1-4ddb-4218-9b36-74764469a656\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u5bfe\u7b56\u9805\u76ee<\/th><th>\u78ba\u8a8d\u30dd\u30a4\u30f3\u30c8<\/th><th>\u5b9f\u88c5\u65b9\u6cd5<\/th><\/tr><\/thead><tbody><tr><td>SQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3<\/td><td>\u30fb\u52d5\u7684SQL\u751f\u6210<br>\u30fb\u30e6\u30fc\u30b6\u30fc\u5165\u529b\u306e\u6271\u3044<\/td><td>\u30fb\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0<br>\u30fbGORM\u30e1\u30bd\u30c3\u30c9\u306e\u4f7f\u7528<\/td><\/tr><tr><td>\u30d1\u30e9\u30e1\u30fc\u30bf\u691c\u8a3c<\/td><td>\u30fb\u5165\u529b\u5024\u306e\u59a5\u5f53\u6027<br>\u30fb\u578b\u5909\u63db\u306e\u5b89\u5168\u6027<\/td><td>\u30fbconstraints\u5b9a\u7fa9<br>\u30fb\u30d0\u30ea\u30c7\u30fc\u30b7\u30e7\u30f3\u5b9f\u88c5<\/td><\/tr><tr><td>\u30a2\u30af\u30bb\u30b9\u5236\u5fa1<\/td><td>\u30fb\u8a8d\u53ef\u30c1\u30a7\u30c3\u30af<br>\u30fb\u30c7\u30fc\u30bf\u306e\u53ef\u8996\u6027<\/td><td>\u30fbSpring Security\u7d71\u5408<br>\u30fb\u30ab\u30b9\u30bf\u30e0\u8a8d\u53ef\u30ed\u30b8\u30c3\u30af<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5b9f\u88c5\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u5165\u529b\u5024\u306e\u691c\u8a3c<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   \/\/ \u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3067\u306e\u5165\u529b\u691c\u8a3c\n   @Validated\n   class ProductController {\n       def save(@Valid Product product) {\n           if (product.hasErrors()) {\n               respond product.errors\n               return\n           }\n           \/\/ \u51e6\u7406\u7d9a\u884c\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>\u30a8\u30e9\u30fc\u51e6\u7406<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   try {\n       Document.executeQuery(query, params)\n   } catch (Exception e) {\n       log.error \"Query execution failed\", e\n       throw new ServiceException(\"\u30c7\u30fc\u30bf\u306e\u53d6\u5f97\u306b\u5931\u6557\u3057\u307e\u3057\u305f\", e)\n   }<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u3092\u9069\u5207\u306b\u5b9f\u88c5\u3059\u308b\u3053\u3068\u3067\u3001\u5b89\u5168\u306a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u958b\u767a\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-48\">6. \u30c6\u30b9\u30c8\u53ef\u80fd\u306aselect\u6587\u306e\u5b9f\u88c5\u65b9\u6cd5<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-49\">\u5358\u4f53\u30c6\u30b9\u30c8\u306e\u4f5c\u6210\u65b9\u6cd5<\/h3>\n\n\n\n<p>Grails\u3067\u306f\u3001select\u6587\u3092\u542b\u3080\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30a2\u30af\u30bb\u30b9\u51e6\u7406\u306e\u30c6\u30b9\u30c8\u3092\u52b9\u7387\u7684\u306b\u5b9f\u88c5\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-50\">\u57fa\u672c\u7684\u306a\u30c6\u30b9\u30c8\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c6\u30b9\u30c8\u5bfe\u8c61\u306e\u30b5\u30fc\u30d3\u30b9\u30af\u30e9\u30b9\nclass ProductService {\n    List&lt;Product&gt; findByCategory(String category) {\n        Product.findAllByCategory(category)\n    }\n\n    List&lt;Product&gt; findByPriceRange(BigDecimal min, BigDecimal max) {\n        Product.createCriteria().list {\n            between('price', min, max)\n            order('price', 'asc')\n        }\n    }\n}\n\n\/\/ \u30c6\u30b9\u30c8\u30af\u30e9\u30b9\n@TestFor(ProductService)\nclass ProductServiceSpec extends Specification {\n    void setupSpec() {\n        \/\/ \u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u30bb\u30c3\u30c8\u30a2\u30c3\u30d7\n        Product.withNewTransaction {\n            new Product(name: \"\u5546\u54c1A\", category: \"\u96fb\u5316\u88fd\u54c1\", price: 1000).save()\n            new Product(name: \"\u5546\u54c1B\", category: \"\u96fb\u5316\u88fd\u54c1\", price: 2000).save()\n            new Product(name: \"\u5546\u54c1C\", category: \"\u66f8\u7c4d\", price: 1500).save()\n        }\n    }\n\n    void \"\u30ab\u30c6\u30b4\u30ea\u306b\u3088\u308b\u691c\u7d22\u306e\u30c6\u30b9\u30c8\"() {\n        when:\n        def results = service.findByCategory(\"\u96fb\u5316\u88fd\u54c1\")\n\n        then:\n        results.size() == 2\n        results.every { it.category == \"\u96fb\u5316\u88fd\u54c1\" }\n    }\n\n    void \"\u4fa1\u683c\u7bc4\u56f2\u306b\u3088\u308b\u691c\u7d22\u306e\u30c6\u30b9\u30c8\"() {\n        when:\n        def results = service.findByPriceRange(1000, 2000)\n\n        then:\n        results.size() == 3\n        results.every { it.price &gt;= 1000 &amp;&amp; it.price &lt;= 2000 }\n        results == results.sort { it.price }  \/\/ \u30bd\u30fc\u30c8\u9806\u306e\u78ba\u8a8d\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-51\">\u30c7\u30fc\u30bf\u30d3\u30eb\u30c0\u30fc\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u30d3\u30eb\u30c0\u30fc\nclass ProductBuilder {\n    private Product product = new Product()\n\n    ProductBuilder withName(String name) {\n        product.name = name\n        this\n    }\n\n    ProductBuilder withCategory(String category) {\n        product.category = category\n        this\n    }\n\n    ProductBuilder withPrice(BigDecimal price) {\n        product.price = price\n        this\n    }\n\n    Product build() {\n        product.save(flush: true)\n        product\n    }\n}\n\n\/\/ \u30d3\u30eb\u30c0\u30fc\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\nclass ProductServiceSpec extends Specification {\n    def setup() {\n        new ProductBuilder()\n            .withName(\"\u5546\u54c1A\")\n            .withCategory(\"\u96fb\u5316\u88fd\u54c1\")\n            .withPrice(1000)\n            .build()\n    }\n\n    void \"\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u306e\u30c6\u30b9\u30c8\"() {\n        given:\n        def service = new ProductService()\n\n        when:\n        def results = service.findByComplexCriteria([\n            category: \"\u96fb\u5316\u88fd\u54c1\",\n            minPrice: 800,\n            maxPrice: 1200\n        ])\n\n        then:\n        results.size() == 1\n        results.first().name == \"\u5546\u54c1A\"\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-52\">\u30e2\u30c3\u30af\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\u306e\u5b9f\u88c5<\/h3>\n\n\n\n<p>\u5916\u90e8\u4f9d\u5b58\u3092\u6301\u3064select\u6587\u306e\u30c6\u30b9\u30c8\u3067\u306f\u3001\u30e2\u30c3\u30af\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u52b9\u7387\u7684\u306a\u30c6\u30b9\u30c8\u304c\u53ef\u80fd\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-53\">\u30ea\u30dd\u30b8\u30c8\u30ea\u30af\u30e9\u30b9\u306e\u30e2\u30c3\u30af<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30ea\u30dd\u30b8\u30c8\u30ea\u30af\u30e9\u30b9\ninterface ProductRepository {\n    List&lt;Product&gt; findByCriteria(Map criteria)\n}\n\nclass ProductRepositoryImpl implements ProductRepository {\n    List&lt;Product&gt; findByCriteria(Map criteria) {\n        Product.createCriteria().list {\n            if (criteria.category) {\n                eq('category', criteria.category)\n            }\n            if (criteria.minPrice) {\n                ge('price', criteria.minPrice)\n            }\n            maxResults(criteria.max ?: 10)\n        }\n    }\n}\n\n\/\/ \u30b5\u30fc\u30d3\u30b9\u30af\u30e9\u30b9\nclass ProductService {\n    ProductRepository productRepository\n\n    List&lt;Product&gt; searchProducts(Map params) {\n        productRepository.findByCriteria(params)\n    }\n}\n\n\/\/ \u30e2\u30c3\u30af\u3092\u4f7f\u7528\u3057\u305f\u30c6\u30b9\u30c8\nclass ProductServiceSpec extends Specification {\n    void \"\u30ea\u30dd\u30b8\u30c8\u30ea\u306e\u30e2\u30c3\u30af\u30c6\u30b9\u30c8\"() {\n        given:\n        def mockRepo = Mock(ProductRepository)\n        def service = new ProductService(productRepository: mockRepo)\n        def criteria = [category: \"\u96fb\u5316\u88fd\u54c1\", minPrice: 1000]\n\n        when:\n        service.searchProducts(criteria)\n\n        then:\n        1 * mockRepo.findByCriteria(criteria) &gt;&gt; [\n            new Product(name: \"\u30c6\u30b9\u30c8\u5546\u54c1\", price: 1500)\n        ]\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-54\">\u30c6\u30b9\u30c8\u5bb9\u6613\u6027\u3092\u9ad8\u3081\u308b\u30b3\u30fc\u30c9\u8a2d\u8a08<\/h3>\n\n\n\n<p>\u30c6\u30b9\u30c8\u3057\u3084\u3059\u3044\u30b3\u30fc\u30c9\u3092\u66f8\u304f\u3053\u3068\u3067\u3001\u4fdd\u5b88\u6027\u3068\u54c1\u8cea\u3092\u5411\u4e0a\u3055\u305b\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-55\">\u4f9d\u5b58\u6027\u6ce8\u5165\u3092\u6d3b\u7528\u3057\u305f\u8a2d\u8a08<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u306e\u62bd\u8c61\u5316\ninterface QueryBuilder {\n    def build(Map params)\n}\n\nclass ProductQueryBuilder implements QueryBuilder {\n    def build(Map params) {\n        def criteria = { criteria -&gt;\n            if (params.category) {\n                criteria.eq('category', params.category)\n            }\n            if (params.minPrice) {\n                criteria.ge('price', params.minPrice)\n            }\n        }\n        criteria\n    }\n}\n\n\/\/ \u30b5\u30fc\u30d3\u30b9\u30af\u30e9\u30b9\nclass ProductService {\n    QueryBuilder queryBuilder\n\n    List&lt;Product&gt; search(Map params) {\n        def query = queryBuilder.build(params)\n        Product.createCriteria().list(query)\n    }\n}\n\n\/\/ \u30c6\u30b9\u30c8\u30af\u30e9\u30b9\nclass ProductServiceSpec extends Specification {\n    void \"\u30af\u30a8\u30ea\u30d3\u30eb\u30c0\u30fc\u306e\u30e2\u30c3\u30af\u30c6\u30b9\u30c8\"() {\n        given:\n        def mockBuilder = Mock(QueryBuilder)\n        def service = new ProductService(queryBuilder: mockBuilder)\n        def params = [category: \"\u96fb\u5316\u88fd\u54c1\"]\n\n        when:\n        service.search(params)\n\n        then:\n        1 * mockBuilder.build(params) &gt;&gt; { criteria -&gt;\n            criteria.eq('category', \"\u96fb\u5316\u88fd\u54c1\")\n        }\n    }\n}<\/pre>\n\n\n\n<p>\u30c6\u30b9\u30c8\u8a2d\u8a08\u306e\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\uff1a<\/p>\n\n\n<div id=\"id-be55e241-11b1-413d-887c-60253066d30d\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u9805\u76ee<\/th><th>\u30dd\u30a4\u30f3\u30c8<\/th><th>\u5b9f\u88c5\u65b9\u6cd5<\/th><\/tr><\/thead><tbody><tr><td>\u30c7\u30fc\u30bf\u6e96\u5099<\/td><td>\u30fb\u30c6\u30b9\u30c8\u30c7\u30fc\u30bf\u306e\u72ec\u7acb\u6027<br>\u30fb\u518d\u5229\u7528\u53ef\u80fd\u306a\u8a2d\u5b9a<\/td><td>\u30fb\u30d3\u30eb\u30c0\u30fc\u30d1\u30bf\u30fc\u30f3<br>\u30fbsetup\u30e1\u30bd\u30c3\u30c9\u306e\u6d3b\u7528<\/td><\/tr><tr><td>\u30e2\u30c3\u30af\u5316<\/td><td>\u30fb\u5916\u90e8\u4f9d\u5b58\u306e\u5206\u96e2<br>\u30fb\u30c6\u30b9\u30c8\u306e\u5236\u5fa1\u6027<\/td><td>\u30fb\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9<br>\u30fb\u4f9d\u5b58\u6027\u6ce8\u5165<\/td><\/tr><tr><td>\u30a2\u30b5\u30fc\u30b7\u30e7\u30f3<\/td><td>\u30fb\u671f\u5f85\u5024\u306e\u660e\u78ba\u5316<br>\u30fb\u30a8\u30c3\u30b8\u30b1\u30fc\u30b9\u306e\u8003\u616e<\/td><td>\u30fbwhere\u53e5\u306e\u6d3b\u7528<br>\u30fb\u4f8b\u5916\u30c6\u30b9\u30c8<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u30c6\u30b9\u30c8\u5b9f\u88c5\u306e\u30c1\u30a7\u30c3\u30af\u30ea\u30b9\u30c8\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>\u30c6\u30b9\u30c8\u306e\u72ec\u7acb\u6027<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   class ProductServiceSpec extends Specification {\n       def setup() {\n           \/\/ \u5404\u30c6\u30b9\u30c8\u306e\u524d\u306b\u30c7\u30fc\u30bf\u3092\u30af\u30ea\u30fc\u30f3\n           Product.withNewTransaction {\n               Product.deleteAll()\n           }\n       }\n   }<\/pre>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\">\n<li>\u30a8\u30c3\u30b8\u30b1\u30fc\u30b9\u306e\u30c6\u30b9\u30c8<\/li>\n<\/ol>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">   void \"\u5883\u754c\u5024\u306e\u30c6\u30b9\u30c8\"() {\n       where:\n       price  | expectCount\n       0      | 0\n       1000   | 1\n       10000  | 0\n   }<\/pre>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u30c6\u30b9\u30c8\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u3092\u6d3b\u7528\u3059\u308b\u3053\u3068\u3067\u3001\u4fdd\u5b88\u6027\u306e\u9ad8\u3044\u9ad8\u54c1\u8cea\u306a\u30b3\u30fc\u30c9\u3092\u7dad\u6301\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-56\">7. \u5b9f\u8df5\u7684\u306a\u30e6\u30fc\u30b9\u30b1\u30fc\u30b9\u3068\u5b9f\u88c5\u4f8b<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-57\">\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u3092\u6301\u3064\u753b\u9762\u306e\u5b9f\u88c5\u4f8b<\/h3>\n\n\n\n<p>E\u30b3\u30de\u30fc\u30b9\u30b5\u30a4\u30c8\u306e\u5546\u54c1\u691c\u7d22\u753b\u9762\u306e\u3088\u3046\u306a\u3001\u8907\u6570\u306e\u691c\u7d22\u6761\u4ef6\u3092\u7d44\u307f\u5408\u308f\u305b\u305f\u5b9f\u88c5\u4f8b\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-58\">\u691c\u7d22\u6761\u4ef6\u3092\u6271\u3046\u30c9\u30e1\u30a4\u30f3\u30af\u30e9\u30b9<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/\/ \u691c\u7d22\u6761\u4ef6\u3092\u8868\u3059\u30b3\u30de\u30f3\u30c9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\nclass ProductSearchCommand implements Validateable {\n    String keyword\n    String category\n    BigDecimal minPrice\n    BigDecimal maxPrice\n    List&lt;String&gt; tags\n    Boolean inStock\n    String sortBy\n    String sortOrder\n    Integer max = 10\n    Integer offset = 0\n\n    static constraints = {\n        keyword nullable: true\n        category nullable: true\n        minPrice nullable: true, min: 0.0\n        maxPrice nullable: true, min: 0.0\n        tags nullable: true\n        inStock nullable: true\n        sortBy nullable: true, inList: ['name', 'price', 'createdAt']\n        sortOrder nullable: true, inList: ['asc', 'desc']\n    }\n\n    \/\/ \u691c\u8a3c\u30ed\u30b8\u30c3\u30af\n    def validate() {\n        if (minPrice &amp;&amp; maxPrice &amp;&amp; minPrice &gt; maxPrice) {\n            errors.rejectValue('minPrice', 'price.range.invalid')\n        }\n    }\n}\n\n\/\/ \u30b5\u30fc\u30d3\u30b9\u30af\u30e9\u30b9\u306e\u5b9f\u88c5\n@Transactional\nclass ProductSearchService {\n    List&lt;Product&gt; search(ProductSearchCommand cmd) {\n        Product.createCriteria().list {\n            createAlias('tags', 't', CriteriaSpecification.LEFT_JOIN)\n\n            \/\/ \u30ad\u30fc\u30ef\u30fc\u30c9\u691c\u7d22\n            if (cmd.keyword) {\n                or {\n                    ilike('name', \"%${cmd.keyword}%\")\n                    ilike('description', \"%${cmd.keyword}%\")\n                }\n            }\n\n            \/\/ \u30ab\u30c6\u30b4\u30ea\u691c\u7d22\n            if (cmd.category) {\n                eq('category', cmd.category)\n            }\n\n            \/\/ \u4fa1\u683c\u7bc4\u56f2\n            if (cmd.minPrice) {\n                ge('price', cmd.minPrice)\n            }\n            if (cmd.maxPrice) {\n                le('price', cmd.maxPrice)\n            }\n\n            \/\/ \u30bf\u30b0\u691c\u7d22\n            if (cmd.tags) {\n                't' {\n                    'in'('name', cmd.tags)\n                }\n                projections {\n                    distinct('id')\n                }\n            }\n\n            \/\/ \u5728\u5eab\u72b6\u614b\n            if (cmd.inStock != null) {\n                gt('stockQuantity', 0)\n            }\n\n            \/\/ \u30bd\u30fc\u30c8\u6761\u4ef6\n            if (cmd.sortBy) {\n                order(cmd.sortBy, cmd.sortOrder ?: 'asc')\n            }\n\n            \/\/ \u30da\u30fc\u30b8\u30f3\u30b0\n            maxResults(cmd.max)\n            firstResult(cmd.offset)\n\n            \/\/ \u30ad\u30e3\u30c3\u30b7\u30e5\u8a2d\u5b9a\n            cache(true)\n        }\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-59\">\u30b3\u30f3\u30c8\u30ed\u30fc\u30e9\u30fc\u3068\u30d3\u30e5\u30fc\u306e\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class ProductController {\n    ProductSearchService productSearchService\n\n    def search(ProductSearchCommand cmd) {\n        if (cmd.hasErrors()) {\n            respond cmd.errors\n            return\n        }\n\n        def results = productSearchService.search(cmd)\n        def total = productSearchService.countTotal(cmd)\n\n        respond([\n            products: results,\n            total: total,\n            params: params\n        ])\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-60\">\u5927\u91cf\u30c7\u30fc\u30bf\u51e6\u7406\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3<\/h3>\n\n\n\n<p>\u5927\u91cf\u306e\u30c7\u30fc\u30bf\u3092\u52b9\u7387\u7684\u306b\u51e6\u7406\u3059\u308b\u5b9f\u88c5\u4f8b\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-61\">\u30d0\u30c3\u30c1\u51e6\u7406\u306b\u3088\u308b\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class BatchProcessingService {\n    static final int BATCH_SIZE = 1000\n\n    def processLargeDataSet() {\n        def offset = 0\n        def processedCount = 0\n\n        while (true) {\n            def products = Product.createCriteria().list {\n                order('id', 'asc')\n                maxResults(BATCH_SIZE)\n                firstResult(offset)\n                readOnly(true)\n            }\n\n            if (!products) {\n                break\n            }\n\n            Product.withNewTransaction { status -&gt;\n                try {\n                    products.each { product -&gt;\n                        processProduct(product)\n                        processedCount++\n                    }\n                } catch (Exception e) {\n                    status.setRollbackOnly()\n                    log.error \"Batch processing failed at offset: $offset\", e\n                    throw e\n                }\n            }\n\n            offset += BATCH_SIZE\n        }\n\n        return processedCount\n    }\n\n    private void processProduct(Product product) {\n        \/\/ \u5546\u54c1\u3054\u3068\u306e\u51e6\u7406\u30ed\u30b8\u30c3\u30af\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-62\">\u30b9\u30c8\u30ea\u30fc\u30df\u30f3\u30b0\u51e6\u7406\u306b\u3088\u308b\u5b9f\u88c5<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class StreamProcessingService {\n    def processDataStream() {\n        def processedCount = 0\n\n        Product.withSession { session -&gt;\n            def query = session.createQuery(\"\"\"\n                FROM Product p\n                WHERE p.status = :status\n                ORDER BY p.id\n            \"\"\")\n            query.setParameter('status', ProductStatus.ACTIVE)\n            query.setFetchSize(1000)\n            query.scroll(ScrollMode.FORWARD_ONLY).with { ScrollableResults results -&gt;\n                try {\n                    while (results.next()) {\n                        def product = results[0] as Product\n                        processProduct(product)\n                        processedCount++\n\n                        if (processedCount % 100 == 0) {\n                            session.flush()\n                            session.clear()\n                        }\n                    }\n                } finally {\n                    results.close()\n                }\n            }\n        }\n\n        return processedCount\n    }\n}<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-63\">\u30ec\u30ac\u30b7\u30fcDB\u3068\u306e\u9023\u643a\u5b9f\u88c5\u4f8b<\/h3>\n\n\n\n<p>\u65e2\u5b58\u306e\u30ec\u30ac\u30b7\u30fc\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3068\u9023\u643a\u3059\u308b\u5b9f\u88c5\u4f8b\u3092\u7d39\u4ecb\u3057\u307e\u3059\u3002<\/p>\n\n\n\n<h4 class=\"wp-block-heading\" id=\"i-64\">\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class LegacyProduct {\n    String productId    \/\/ \u30ec\u30ac\u30b7\u30fcDB\u4e0a\u306eID\n    String productName  \/\/ \u5546\u54c1\u540d\n    BigDecimal price   \/\/ \u4fa1\u683c\n\n    static mapping = {\n        table 'TBL_PRODUCT'  \/\/ \u30ec\u30ac\u30b7\u30fc\u30c6\u30fc\u30d6\u30eb\u540d\n        version false        \/\/ \u30d0\u30fc\u30b8\u30e7\u30f3\u7ba1\u7406\u7121\u52b9\n        id column: 'PRODUCT_ID', generator: 'assigned'\n        productName column: 'PRODUCT_NM'\n        price column: 'PRICE_AMT'\n    }\n\n    \/\/ NULL\u8a31\u5bb9\u30d5\u30a3\u30fc\u30eb\u30c9\u306e\u5b9a\u7fa9\n    static constraints = {\n        productName nullable: true\n        price nullable: true\n    }\n}\n\n\/\/ \u30ec\u30ac\u30b7\u30fcDB\u30a2\u30af\u30bb\u30b9\u7528\u30b5\u30fc\u30d3\u30b9\nclass LegacyProductService {\n    def findProducts(Map criteria) {\n        def query = \"\"\"\n            FROM LegacyProduct p\n            WHERE 1=1\n        \"\"\"\n        def params = [:]\n\n        if (criteria.productName) {\n            query += \" AND p.productName LIKE :productName\"\n            params.productName = \"%${criteria.productName}%\"\n        }\n\n        if (criteria.minPrice) {\n            query += \" AND p.price &gt;= :minPrice\"\n            params.minPrice = criteria.minPrice\n        }\n\n        LegacyProduct.executeQuery(query, params)\n    }\n\n    \/\/ \u30c7\u30fc\u30bf\u540c\u671f\u51e6\u7406\n    @Transactional\n    def synchronizeWithModernDB() {\n        def batchSize = 100\n        def processed = 0\n\n        LegacyProduct.createCriteria().list {\n            projections {\n                property('productId')\n            }\n        }.collate(batchSize).each { batch -&gt;\n            Product.withNewTransaction { status -&gt;\n                try {\n                    batch.each { legacyId -&gt;\n                        syncProduct(legacyId)\n                        processed++\n                    }\n                } catch (Exception e) {\n                    status.setRollbackOnly()\n                    log.error \"Sync failed for batch\", e\n                    throw e\n                }\n            }\n        }\n\n        return processed\n    }\n\n    private void syncProduct(String legacyId) {\n        def legacyProduct = LegacyProduct.get(legacyId)\n        def modernProduct = Product.findByLegacyId(legacyId) ?: new Product(legacyId: legacyId)\n\n        modernProduct.with {\n            name = legacyProduct.productName\n            price = legacyProduct.price\n            \/\/ \u305d\u306e\u4ed6\u306e\u9805\u76ee\u306e\u30de\u30c3\u30d4\u30f3\u30b0\n        }\n\n        modernProduct.save(flush: true)\n    }\n}<\/pre>\n\n\n\n<p class=\"is-style-sango-paragraph-memo-alt\">\u5b9f\u88c5\u306e\u30dd\u30a4\u30f3\u30c8\uff1a<\/p>\n\n\n<div id=\"id-5cda869e-1880-4f8a-8d94-8204efda0ee5\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u30e6\u30fc\u30b9\u30b1\u30fc\u30b9<\/th><th>\u91cd\u8981\u306a\u8003\u616e\u70b9<\/th><th>\u63a8\u5968\u3055\u308c\u308b\u5b9f\u88c5\u65b9\u6cd5<\/th><\/tr><\/thead><tbody><tr><td>\u8907\u96d1\u306a\u691c\u7d22<\/td><td>\u30fb\u691c\u7d22\u6761\u4ef6\u306e\u59a5\u5f53\u6027\u691c\u8a3c<br>\u30fb\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316<\/td><td>\u30fb\u30b3\u30de\u30f3\u30c9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8<br>\u30fb\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u8a2d\u8a08<\/td><\/tr><tr><td>\u5927\u91cf\u30c7\u30fc\u30bf\u51e6\u7406<\/td><td>\u30fb\u30e1\u30e2\u30ea\u7ba1\u7406<br>\u30fb\u30c8\u30e9\u30f3\u30b6\u30af\u30b7\u30e7\u30f3\u5236\u5fa1<\/td><td>\u30fb\u30d0\u30c3\u30c1\u51e6\u7406<br>\u30fb\u30b9\u30c8\u30ea\u30fc\u30df\u30f3\u30b0\u51e6\u7406<\/td><\/tr><tr><td>\u30ec\u30ac\u30b7\u30fc\u9023\u643a<\/td><td>\u30fb\u30c7\u30fc\u30bf\u6574\u5408\u6027<br>\u30fb\u30a8\u30e9\u30fc\u30cf\u30f3\u30c9\u30ea\u30f3\u30b0<\/td><td>\u30fb\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a<br>\u30fb\u540c\u671f\u51e6\u7406\u306e\u5b9f\u88c5<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<p>\u3053\u308c\u3089\u306e\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u5b9f\u969b\u306e\u30d3\u30b8\u30cd\u30b9\u8981\u4ef6\u306b\u5bfe\u5fdc\u3057\u305f\u5805\u7262\u306a\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u69cb\u7bc9\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"i-65\">\u307e\u3068\u3081\uff1aGrails\u306eselect\u6587\u5b9f\u88c5\u306b\u304a\u3051\u308b7\u3064\u306e\u91cd\u8981\u30dd\u30a4\u30f3\u30c8<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-66\">1. \u57fa\u672c\u8a2d\u8a08\u306e\u91cd\u8981\u6027<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GORM\u3092\u6d3b\u7528\u3057\u305f\u9069\u5207\u306a\u8a2d\u8a08\u304c\u4fdd\u5b88\u6027\u3068\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u306e\u57fa\u76e4\u3068\u306a\u308a\u307e\u3059<\/li>\n\n\n\n<li>\u52d5\u7684\u30d5\u30a1\u30a4\u30f3\u30c0\u30fc\u3001where\u30af\u30a8\u30ea\u3001HQL\u306e\u7279\u6027\u3092\u7406\u89e3\u3057\u3001\u9069\u5207\u306b\u4f7f\u3044\u5206\u3051\u308b\u3053\u3068\u304c\u91cd\u8981\u3067\u3059<\/li>\n\n\n\n<li>\u30c9\u30e1\u30a4\u30f3\u30e2\u30c7\u30eb\u306e\u8a2d\u8a08\u6642\u70b9\u3067\u30af\u30a8\u30ea\u306e\u5b9f\u884c\u52b9\u7387\u3092\u8003\u616e\u3059\u308b\u3053\u3068\u3067\u3001\u5f8c\u3005\u306e\u554f\u984c\u3092\u9632\u3052\u307e\u3059<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-67\">2. \u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u306e\u4f7f\u3044\u5206\u3051<\/h3>\n\n\n<div id=\"id-7341fab1-7973-45c1-8d66-05e9d468a2f9\">\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>\u30d1\u30bf\u30fc\u30f3<\/th><th>\u4f7f\u7528\u5834\u9762<\/th><th>\u30e1\u30ea\u30c3\u30c8<\/th><\/tr><\/thead><tbody><tr><td>findBy<\/td><td>\u5358\u7d14\u306a\u691c\u7d22<\/td><td>\u76f4\u611f\u7684\u3067\u5b9f\u88c5\u304c\u5bb9\u6613<\/td><\/tr><tr><td>where<\/td><td>\u8907\u6570\u6761\u4ef6\u306e\u7d44\u307f\u5408\u308f\u305b<\/td><td>\u578b\u5b89\u5168\u6027\u304c\u9ad8\u3044<\/td><\/tr><tr><td>HQL<\/td><td>\u8907\u96d1\u306a\u7d50\u5408\u30fb\u96c6\u8a08<\/td><td>\u67d4\u8edf\u306a\u691c\u7d22\u304c\u53ef\u80fd<\/td><\/tr><\/tbody><\/table><\/figure>\n<\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"i-68\">3. \u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u6700\u9069\u5316\u306e\u30dd\u30a4\u30f3\u30c8<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>N+1\u554f\u984c\u306e\u56de\u907f\u306b\u306f\u9069\u5207\u306a\u30d5\u30a7\u30c3\u30c1\u6226\u7565\u306e\u9078\u629e\u304c\u4e0d\u53ef\u6b20<\/li>\n\n\n\n<li>\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u306e\u52b9\u679c\u7684\u306a\u6d3b\u7528\u3067\u30af\u30a8\u30ea\u306e\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3092\u5927\u5e45\u306b\u6539\u5584\u53ef\u80fd<\/li>\n\n\n\n<li>\u30ad\u30e3\u30c3\u30b7\u30e5\u6a5f\u80fd\u306e\u9069\u5207\u306a\u4f7f\u7528\u3067\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u5168\u4f53\u306e\u5fdc\u7b54\u6027\u3092\u5411\u4e0a<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-69\">4. \u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u5bfe\u7b56\u306e\u5fb9\u5e95<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u30d1\u30e9\u30e1\u30fc\u30bf\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u306b\u3088\u308bSQL\u30a4\u30f3\u30b8\u30a7\u30af\u30b7\u30e7\u30f3\u5bfe\u7b56<\/li>\n\n\n\n<li>\u9069\u5207\u306a\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u306e\u5b9f\u88c5<\/li>\n\n\n\n<li>\u5165\u529b\u5024\u306e\u691c\u8a3c\u3068\u5b89\u5168\u306a\u578b\u5909\u63db<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-70\">5. \u30c6\u30b9\u30c8\u5bb9\u6613\u6027\u306e\u78ba\u4fdd<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u5358\u4f53\u30c6\u30b9\u30c8\u306e\u4f5c\u6210<\/li>\n\n\n\n<li>\u30e2\u30c3\u30af\u3092\u6d3b\u7528\u3057\u305f\u5916\u90e8\u4f9d\u5b58\u306e\u5206\u96e2<\/li>\n\n\n\n<li>\u30c6\u30b9\u30c8\u5bb9\u6613\u6027\u3092\u8003\u616e\u3057\u305f\u30b3\u30fc\u30c9\u8a2d\u8a08<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-71\">6. \u5b9f\u8df5\u7684\u306a\u5b9f\u88c5\u306e\u305f\u3081\u306b<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u8907\u96d1\u306a\u691c\u7d22\u6761\u4ef6\u306f\u30b3\u30de\u30f3\u30c9\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3067\u6574\u7406<\/li>\n\n\n\n<li>\u5927\u91cf\u30c7\u30fc\u30bf\u51e6\u7406\u306b\u306f\u30d0\u30c3\u30c1\u51e6\u7406\u3084\u30b9\u30c8\u30ea\u30fc\u30df\u30f3\u30b0\u51e6\u7406\u3092\u6d3b\u7528<\/li>\n\n\n\n<li>\u30ec\u30ac\u30b7\u30fc\u30b7\u30b9\u30c6\u30e0\u3068\u306e\u9023\u643a\u6642\u306f\u9069\u5207\u306a\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u304c\u91cd\u8981<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-72\">\u4eca\u5f8c\u306e\u767a\u5c55\u306b\u5411\u3051\u3066<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u65b0\u3057\u3044Grails\u30d0\u30fc\u30b8\u30e7\u30f3\u306e\u6a5f\u80fd\u3092\u7a4d\u6975\u7684\u306b\u6d3b\u7528<\/li>\n\n\n\n<li>\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u30e2\u30cb\u30bf\u30ea\u30f3\u30b0\u306e\u7d99\u7d9a\u7684\u306a\u5b9f\u65bd<\/li>\n\n\n\n<li>\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3078\u306e\u8fc5\u901f\u306a\u5bfe\u5fdc<\/li>\n<\/ul>\n\n\n\n<p>\u3053\u308c\u3089\u306e\u8981\u7d20\u3092\u9069\u5207\u306b\u7d44\u307f\u5408\u308f\u305b\u308b\u3053\u3068\u3067\u3001\u4fdd\u5b88\u6027\u304c\u9ad8\u304f\u3001\u30d1\u30d5\u30a9\u30fc\u30de\u30f3\u30b9\u3068\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u3092\u4e21\u7acb\u3057\u305fGrails\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u69cb\u7bc9\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"i-73\">\u53c2\u8003\u30ea\u30bd\u30fc\u30b9<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/docs.grails.org\/\">Grails\u516c\u5f0f\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/gorm.grails.org\/\">GORM\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/grails-plugins.github.io\/grails-spring-security-core\/\">Spring Security\u30d7\u30e9\u30b0\u30a4\u30f3<\/a><\/li>\n<\/ul>\n\n\n\n<p>\u672c\u8a18\u4e8b\u3067\u7d39\u4ecb\u3057\u305f\u5b9f\u88c5\u30d1\u30bf\u30fc\u30f3\u3084\u30d9\u30b9\u30c8\u30d7\u30e9\u30af\u30c6\u30a3\u30b9\u3092\u57fa\u306b\u3001\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u8981\u4ef6\u306b\u5408\u308f\u305b\u3066\u6700\u9069\u306a\u5b9f\u88c5\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Warning: Undefined array key &#8220;is_admin&#8221; in \/home\/xs392991\/dexall.co.jp\/public_html\/articles\/wp-content\/themes\/ &#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":{"0":"post-783","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-uncategorized","7":"nothumb"},"_links":{"self":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/783","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=783"}],"version-history":[{"count":2,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/783\/revisions"}],"predecessor-version":[{"id":3490,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=\/wp\/v2\/posts\/783\/revisions\/3490"}],"wp:attachment":[{"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=783"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=783"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dexall.co.jp\/articles\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=783"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}