JPA (EclipseLink) में अनमैप्ड डेटाबेस कॉलम के साथ क्वेरी
JPA के पीछे मुख्य विचार ऑब्जेक्ट-रिलेशनल मैपिंग है, जिसके कारण हम क्वेरी बनाते समय डेटाबेस कॉलम के बारे में भूल सकते हैं और मैप्ड ऑब्जेक्ट गुणों के साथ काम कर सकते हैं। हालाँकि, यदि हम एक ऐसे कॉलम को संदर्भित करना चाहते हैं जो मैप नहीं किया गया है, तो जिस तरह से हम क्वेरी बनाते हैं, उसके आधार पर, JPA-विशिष्ट कार्यान्वयन, जैसे कि EclipseLink द्वारा प्रदान किए गए इंटरफ़ेस का उपयोग करना आवश्यक हो सकता है।
उदाहरण के लिए, आइए एक साधारण उपयोगकर्ता तालिका लें:
CREATE TABLE users
(
id BIGINT GENERATED BY DEFAULT AS IDENTITY NOT NULL,
hidden BOOLEAN DEFAULT false,
name VARCHAR(255),
PRIMARY KEY (id)
);
INSERT INTO users (name, hidden) VALUES ('Adam', true);
INSERT INTO users (name, hidden) VALUES ('Damian', false);
INSERT INTO users (name, hidden) VALUES ('Emma', true);
INSERT INTO users (name, hidden) VALUES ('Alice', false);
एंटिटी क्लास की परिभाषा में, मैं जानबूझकर hidden
कॉलम के लिए मैपिंग को छोड़ देता हूं:
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Getter
@Setter
@ToString(exclude = "id")
@Entity
@Table(name="users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
अब मान लीजिए कि हम छिपे हुए कॉलम के आधार पर एक क्वेरी बनाना चाहते हैं, हम क्वेरी निर्माण के साथ शुरू कर सकते हैं:
- JPA CriteriaBuilder इंटरफ़ेस जो मैप्ड फ़ील्ड के माध्यम से संदर्भ की अनुमति देता है। कॉलम के लिए एक सीधा संदर्भ बनाने के लिए आपको JPA कार्यान्वयन के इंटरफ़ेस का उपयोग करने की आवश्यकता है। EclipseLink के मामले में, चरण होंगे:
- CriteriaBuilder को JpaCriteriaBuilder में डाउनकास्ट करना;
- एंटिटी संदर्भ को EL-विशिष्ट
org.eclipse.persistence.expressions.Expression
में परिवर्तित करना,getField()
के माध्यम से कॉलम संदर्भ बनाना और इसे JPA-संगत रूप में वापस परिवर्तित करना; - प्रासंगिक शर्त जोड़ना;
- JPQL सिंटैक्स - ऊपर की तरह - हम EL-विशिष्ट सिंटैक्स का उपयोग कर सकते हैं:
WHERE SQL('hidden = true')
; - एक नेटिव क्वेरी।
import org.eclipse.persistence.jpa.JpaCriteriaBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import java.util.List;
@SpringBootTest
class DemoApplicationTests {
@PersistenceContext
EntityManager em;
@Test
void testUnmappedFieldCriteria() {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
List<User> users = em.createQuery(criteria).getResultList();
System.out.println("All users: " + users);
// #1
JpaCriteriaBuilder jpaBuilder = (JpaCriteriaBuilder) builder;
Expression<Boolean> hiddenField = jpaBuilder.fromExpression(
jpaBuilder.toExpression(criteria.from(User.class)).getField("hidden"),
Boolean.class
);
users = em.createQuery(criteria.where(builder.equal(hiddenField, false)))
.getResultList();
System.out.println("#1 Visible users using JpaCriteriaBuilder: " + users);
// #2
users = em.createQuery("SELECT u FROM User u WHERE SQL('hidden = true')", User.class)
.getResultList();
System.out.println("#2 Hidden users using JPQL (EL-flavored): " + users);
// #3
users = em.createNativeQuery("SELECT * FROM users WHERE hidden = true", User.class)
.getResultList();
System.out.println("#3 Hidden users using native query: " + users);
}
}
दिखाए गए सभी मामलों में, EclipseLink अपेक्षित परिणाम लौटाते हुए सही क्वेरी उत्पन्न करता है:
[EL Fine]: sql: 2022-01-09 13:51:28.215--ServerSession(2027837674)--Connection(1139915666)--Thread(Thread[main,5,main])--SELECT ID, NAME FROM users
All users: [User(name=Adam), User(name=Damian), User(name=Emma), User(name=Alice)]
[EL Fine]: sql: 2022-01-09 13:51:28.258--ServerSession(2027837674)--Connection(1139915666)--Thread(Thread[main,5,main])--SELECT ID, NAME FROM users WHERE (hidden = ?)
bind => [false]
#1 Visible users using JpaCriteriaBuilder: [User(name=Damian), User(name=Alice)]
[EL Fine]: sql: 2022-01-09 13:51:28.616--ServerSession(2027837674)--Connection(1139915666)--Thread(Thread[main,5,main])--SELECT ID, NAME FROM users WHERE hidden = true
#2 Hidden users using JPQL (EL-flavored): [User(name=Adam), User(name=Emma)]
[EL Fine]: sql: 2022-01-09 13:51:28.634--ServerSession(2027837674)--Connection(1139915666)--Thread(Thread[main,5,main])--SELECT * FROM users WHERE hidden = true
#3 Hidden users using native query: [User(name=Adam), User(name=Emma)]
अन्य JPA कार्यान्वयन के लिए, आप समान इंटरफेस पा सकते हैं। उदाहरण के लिए, Hibernate Restrictions.sqlRestriction विधियों की पेशकश करता है, जिनका उपयोग समान परिणाम प्राप्त करने के लिए मानदंडों के निर्माण के दौरान किया जा सकता है।