استفاده از Projections در  Spring Data JPA

دونوع پیاده سازی Interface-base و class-base دارد، که در اینجا ما به نوع interface-base می پردازیم. یه شمای کلی به صورت زیر:داستان چیه:یک جدول داریم به اسم درخواست ها، درون این جدول کلی فیلد و روابط با جداول دیگر است. زمانی که برای واکشی اطلاعات از دیتابیس از Jpa استفاده می کنیم ، به صورت معمول کلاس entity رو به عنوان Object برگشتی در اینترفیس repository (مانند زیر) قرار می دیم.@Repository public interface PsmRequestRepository extends MiddleRepository<PsmRequestChangesEnt, Long> { PsmRequestChangesEnt findByShebaName(String shebaName); }در نتیجه بعد از فراخوانی این متد، تمام فیلد ها و روابطی که در entity تعریف کردیم مقداردهی و برگردانده می شود.ولی بعضی وقتی ها لازم نیست که در زمان fetch کردن داده ها، کل فیلد های entity و تمام روابطی که ساختیم رو برگردونیم و ما بر اساس نیازمون (سرویس هامون) تنها یک سری فیلد ها را می خواهیم. برای مثال در بالا بر اساس فیلد ReqType فقط برخی از فیلد ها پر می شود ، گاهی فقط فیلد های مربوط به آدرس(MainStreet,SubStreet ,...)، گاهی فیلدهای مربوط به شماره و گاهی هم فیلدهای مربوط به اطلاعات صنف و صنف تکمیلی(GILD_POM_GULD_ID وGILD_POM_GLGR_ID کلید خارجی به دو جدول دیگر) در این زمان یکی از روش ها استفاده از Interface projections.فیلد TERM_POM_TRMN_ID یک کلید خارجی به جدول ترمینال است که پدر جدول درخواست ها می باشد با مقادیر شناسه- کد و .... . یک interface پدر تعریف کردم که اطلاعات پدر رو داخلش گذاشتم: ویژگی اینترفیس باید چی باشه؟ هر فیلدی را که می خواهیم jpa برای ما از دیتابیس برگردونه رو داخل اینترفیس قرار می دهیم ولی متد های getter آن ها را.(دقیقا باید هم نام متغییر های تعریف شده در کلاس entity اصلی باشد تا به درستی توسط Jpa پر شود)public interface RequestData { Long getId(); Long getTerminalNo(); String getStoreName(); }یه اینترفیس دیگه ام ایجاد کردم برای حالتی که نیاز به برگردوندن فیلد های آدرس از جدول درخواست ها دارم:این ایترفیس فیلد های اینترفیس پدر رو نیز بر می گردونه چون از اینترفیس پدر extends کردیم:public interface AddressOnly extends RequestData{ String getPreNum(); String getPhone(); String getMainStreet(); String getSubStreet(); String getAlley(); String getPostCode(); String getFloorAndUnit(); String getPlaque(); String getDesc(); //------------------------------------------------------------------------------ @Value(&quot#{target.preNum+ ' ' + target.phone}&quot) String getPhoneNumber() ; //یا : default String getPhoneNumber() { return getPreNum().concat(getPhone()); } }می توانیم از ترکیب متغییر های مختلف نیز متغییر جدید ایجاد کنیم که دو مدلش در بالا ذکر شده است. (getPhoneNumber وقتی پر می شود مقدار فیلد های پیش شماره و شماره را به هم وصل می کند و فیلد جدید شماره تلفن را برای ما ایجاد می کند، برای مواردی چون نام و نام خانوادگی که اطلاعات رو در دو ستون جدا ذخیره می کنید خیلی به درد می خوره)نمونه فراخوانی خروجی اینترفیس در repository مربوطه :-من در این مورد محدود کردم که تنها اینترفیسی ها که از جنس RequestData هستند را قبول کند @Repository public interface PsmRequestRepository extends MiddleRepository<PsmRequestChangesEnt, Long> { <RW extends RequestData> RW findByStatusAndShebaName(StatusEnum status, String shebaName, Class<RW> type); ... } نحوه ی فراخوانی متد :public AddressOnly findByStatusAndShebaName( StatusEnum status,String shebaName) throws FrameworkException { return reqService.findByStatusAndShebaName(status, shebaName, AddressOnly.class); }نمایش خروجی :ورودی وضعیت و شماره شبا، خروجی تنها فیلد های آدرس مربوط به آن درخواست ، نه کل فیلد ها :@GetMapping(value = &quot/req/{shebaName}&quot, produces = &quotapplication/json;charset=UTF-8&quot) public AddressOnly reqLoadByShebaName(@PathVariable Long shebaName) throws FrameworkException { return addressService.findByStatusAndShebaName(code, StatusEnum.INSTALLED); }نکته: حتی می تونیم در یک اینترفیس یک اینترفیس دیگه هم قرار دهیم. در زیر متغیرPsmGuildEnt ،یک Object از کلاس صنف است که ما فقط می خواهیم در زمان fetch کردن داده ها، اطلاعات فیلد های کد و عنوان صنف را بر گرداند.public interface StoreName_GuildOnly extends RequestData { GuildOnly getPsmGuildEnt(); interface GuildOnly{ Long getCode(); String getTitle(); } }