अतिरिक्त कॉलम के साथ कई-से-कई एसोसिएशन तालिका का मानचित्रण करना


130

मेरे डेटाबेस में 3 तालिकाएँ हैं: उपयोगकर्ता और सेवा संस्थाओं के कई-से-कई संबंध हैं और इस तरह से SERVICE_USER तालिका के साथ जुड़ गए हैं:

USERS - SERVICE_USER - सेवाएँ

SERVICE_USER तालिका में अतिरिक्त ब्लॉक किया गया कॉलम है।

इस तरह की मैपिंग करने का सबसे अच्छा तरीका क्या है? ये मेरी एंटिटी क्लासेस हैं

@Entity
@Table(name = "USERS")
public class User implements java.io.Serializable {

private String userid;
private String email;

@Id
@Column(name = "USERID", unique = true, nullable = false,)
public String getUserid() {
return this.userid;
}

.... some get/set methods
}

@Entity
@Table(name = "SERVICES")
public class CmsService implements java.io.Serializable {
private String serviceCode;

@Id
@Column(name = "SERVICE_CODE", unique = true, nullable = false, length = 100)
public String getServiceCode() {
return this.serviceCode;
}
.... some additional fields and get/set methods
}

मैंने इस उदाहरण का अनुसरण किया है http://giannigar.wordpress.com/2009/09/04/m ... using-jpa / Here is some test code:

User user = new User();
user.setEmail("e2");
user.setUserid("ui2");
user.setPassword("p2");

CmsService service= new CmsService("cd2","name2");

List<UserService> userServiceList = new ArrayList<UserService>();

UserService userService = new UserService();
userService.setService(service);
userService.setUser(user);
userService.setBlocked(true);
service.getUserServices().add(userService);

userDAO.save(user);

समस्या यह है कि हाइबरनेट उपयोगकर्ता ऑब्जेक्ट और UserService एक बनी रहती है। CmsService ऑब्जेक्ट के साथ कोई सफलता नहीं

मैंने EAGER लाने की कोशिश की - कोई प्रगति नहीं

क्या यह संभव है कि मैं ऊपर दिए गए मानचित्रण के साथ जिस व्यवहार की अपेक्षा कर रहा हूं उसे प्राप्त करना संभव है?

हो सकता है कि अतिरिक्त कॉलम के साथ कई ज्वाइन टेबल के लिए मैपिंग का कुछ और सुरुचिपूर्ण तरीका हो?

जवाबों:


192

चूंकि SERVICE_USER तालिका एक शुद्ध ज्वाइन टेबल नहीं है, लेकिन इसमें अतिरिक्त कार्यात्मक क्षेत्र (अवरुद्ध) हैं, इसलिए आपको इसे एक इकाई के रूप में मैप करना होगा, और उपयोगकर्ता और सेवा के बीच कई संबंध को दो OneToMany संघों में विघटित करना चाहिए: एक उपयोगकर्ता कई उपयोगकर्ता सेवाएँ हैं, और एक सेवा में कई उपयोगकर्ता सेवाएँ हैं।

आपने हमें सबसे महत्वपूर्ण हिस्सा नहीं दिखाया है: मानचित्रण और अपनी संस्थाओं के बीच संबंधों का आरंभ (यानी जिस हिस्से में आपको समस्या है)। तो मैं आपको दिखाता हूं कि यह कैसा दिखना चाहिए।

यदि आप रिश्तों को द्विदिश बनाते हैं, तो आपको इस प्रकार होना चाहिए

class User {
    @OneToMany(mappedBy = "user")
    private Set<UserService> userServices = new HashSet<UserService>();
}

class UserService {
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "service_code")
    private Service service;

    @Column(name = "blocked")
    private boolean blocked;
}

class Service {
    @OneToMany(mappedBy = "service")
    private Set<UserService> userServices = new HashSet<UserService>();
}

यदि आप अपने रिश्तों पर कोई रोक नहीं लगाते हैं, तो आपको सभी संस्थाओं को बचाना / बचाना होगा। हालाँकि रिश्ते के केवल स्वयं के पक्ष (यहां, उपयोगकर्ता सेवा पक्ष) को आरंभीकृत किया जाना चाहिए, यह सुनिश्चित करने के लिए कि दोनों पक्ष सुसंगत हैं, यह एक अच्छा अभ्यास है।

User user = new User();
Service service = new Service();
UserService userService = new UserService();

user.addUserService(userService);
userService.setUser(user);

service.addUserService(userService);
userService.setService(service);

session.save(user);
session.save(service);
session.save(userService);

2
बस जोड़ने के लिए .. जबकि यह मेरी राय में सबसे अच्छा तरीका है (मैं हमेशा प्रदर्शन कारणों से एक इकाई के रूप में एफके के मालिक होने वाली चीज को मैप करना पसंद करता हूं), यह वास्तव में एकमात्र तरीका नहीं है। आप एक घटक के रूप में SERVICE_USER तालिका से मानों को मैप कर सकते हैं (JPA एक एम्बेड करने योग्य कॉल करता है) और @ElementCollectionउपयोगकर्ता (और दोनों) से या तो उपयोगकर्ता और सेवा संस्थाओं का उपयोग करते हैं।
स्टीव आइबर्स

6
उपयोगकर्ता सेवा तालिका की प्राथमिक कुंजी के बारे में क्या? यह उपयोगकर्ता और सेवा विदेशी कुंजी का संयोजन होना चाहिए। क्या वह मैप किया गया है?
जोनास ग्रोगर

24
मैं ऐसा नहीं करूंगा। समग्र चाबियाँ दर्दनाक, अक्षम, और हाइबरनेट समग्र कुंजियों का उपयोग नहीं करने की सलाह देती हैं। बस किसी भी अन्य इकाई के लिए एक ऑटो-जनरेटेड आईडी का उपयोग करें, और जीवन बहुत सरल हो जाएगा। की एकता सुनिश्चित करने के लिए [userFK, serviceFK], एक अद्वितीय बाधा का उपयोग करें।
बजे जेबी निज़ेट

1
@GaryKephart: अपने खुद के कोड और अपने स्वयं के मानचित्रण के साथ, अपना प्रश्न पूछें।
जेबी निज़ेट

1
@gstackoverflow: हाइबरनेट 4 उस संबंध में कुछ भी नहीं बदलता है। मैं वास्तव में नहीं देखता कि यह कैसे अयोग्य है।
जेबी निज़ेट

5

मैं एक्सएमएल फाइल कॉन्फ़िगरेशन में हाइबरनेट के साथ अतिरिक्त कॉलम (एस) के साथ कई-टू-कई एसोसिएशन टेबल को मैप करने का एक तरीका खोजता हूं।

मान लें कि दो टेबल 'ए' और 'सी' हैं, जिनमें से कई में 'अतिरिक्त' नाम के कॉलम के साथ कई जुड़ाव हैं। क्योंकि मुझे कोई पूर्ण उदाहरण नहीं मिला, यहाँ मेरा कोड है। आशा है कि यह मदद करेगा :)।

यहां सबसे पहले जावा ऑब्जेक्ट है।

public class A implements Serializable{  

    protected int id;
    // put some others fields if needed ...   
    private Set<AC> ac = new HashSet<AC>();

    public A(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Set<AC> getAC() {
        return ac;
    }

    public void setAC(Set<AC> ac) {
        this.ac = ac;
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        final int prime = 97;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof A))
            return false;
        final A other = (A) obj;
        if (id != other.getId())
            return false;
        return true;
    }

}

public class C implements Serializable{

    protected int id;
    // put some others fields if needed ...    

    public C(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    /** {@inheritDoc} */
    @Override
    public int hashCode() {
        final int prime = 98;
        int result = 1;
        result = prime * result + id;
        return result;
    }

    /** {@inheritDoc} */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (!(obj instanceof C))
            return false;
        final C other = (C) obj;
        if (id != other.getId())
            return false;
        return true;
    }

}

अब, हमें एसोसिएशन तालिका बनानी होगी। पहला कदम एक जटिल प्राथमिक कुंजी (a.id, c.id) का प्रतिनिधित्व करने वाली वस्तु बनाना है।

public class ACId implements Serializable{

    private A a;
    private C c;

    public ACId() {
        super();
    }

    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
    public C getC() {
        return c;
    }
    public void setC(C c) {
        this.c = c;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((a == null) ? 0 : a.hashCode());
        result = prime * result
                + ((c == null) ? 0 : c.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        ACId other = (ACId) obj;
        if (a == null) {
            if (other.a != null)
                return false;
        } else if (!a.equals(other.a))
            return false;
        if (c == null) {
            if (other.c != null)
                return false;
        } else if (!c.equals(other.c))
            return false;
        return true;
    }
}

अब एसोसिएशन ऑब्जेक्ट को खुद बनाते हैं।

public class AC implements java.io.Serializable{

    private ACId id = new ACId();
    private String extra;

    public AC(){

    }

    public ACId getId() {
        return id;
    }

    public void setId(ACId id) {
        this.id = id;
    }

    public A getA(){
        return getId().getA();
    }

    public C getC(){
        return getId().getC();
    }

    public void setC(C C){
        getId().setC(C);
    }

    public void setA(A A){
        getId().setA(A);
    }

    public String getExtra() {
        return extra;
    }

    public void setExtra(String extra) {
        this.extra = extra;
    }

    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;

        AC that = (AC) o;

        if (getId() != null ? !getId().equals(that.getId())
                : that.getId() != null)
            return false;

        return true;
    }

    public int hashCode() {
        return (getId() != null ? getId().hashCode() : 0);
    }
}

इस बिंदु पर, हाइबरनेट xml कॉन्फ़िगरेशन के साथ हमारी सभी कक्षाओं को मैप करने का समय है।

A.hbm.xml और C.hxml.xml (समान को शांत करें)।

<class name="A" table="a">
        <id name="id" column="id_a" unsaved-value="0">
            <generator class="identity">
                <param name="sequence">a_id_seq</param>
            </generator>
        </id>
<!-- here you should map all others table columns -->
<!-- <property name="otherprop" column="otherprop" type="string" access="field" /> -->
    <set name="ac" table="a_c" lazy="true" access="field" fetch="select" cascade="all">
        <key>
            <column name="id_a" not-null="true" />
        </key>
        <one-to-many class="AC" />
    </set>
</class>

<class name="C" table="c">
        <id name="id" column="id_c" unsaved-value="0">
            <generator class="identity">
                <param name="sequence">c_id_seq</param>
            </generator>
        </id>
</class>

और फिर एसोसिएशन मैपिंग फ़ाइल, a_c.hbm.xml।

<class name="AC" table="a_c">
    <composite-id name="id" class="ACId">
        <key-many-to-one name="a" class="A" column="id_a" />
        <key-many-to-one name="c" class="C" column="id_c" />
    </composite-id>
    <property name="extra" type="string" column="extra" />
</class>

यहाँ परीक्षण करने के लिए कोड नमूना है।

A = ADao.get(1);
C = CDao.get(1);

if(A != null && C != null){
    boolean exists = false;
            // just check if it's updated or not
    for(AC a : a.getAC()){
        if(a.getC().equals(c)){
            // update field
            a.setExtra("extra updated");
            exists = true;
            break;
        }
    }

    // add 
    if(!exists){
        ACId idAC = new ACId();
        idAC.setA(a);
        idAC.setC(c);

        AC AC = new AC();
        AC.setId(idAC);
        AC.setExtra("extra added"); 
        a.getAC().add(AC);
    }

    ADao.save(A);
}

2

जैसा कि पहले कहा गया है, जेपीए के साथ, अतिरिक्त कॉलम रखने का मौका देने के लिए, आपको एक OneToMany संबंधों के बजाय दो OneToMany संघों का उपयोग करने की आवश्यकता है। आप ऑटोजेनरेटेड मूल्यों के साथ एक कॉलम भी जोड़ सकते हैं; इस तरह, यह उपयोगी होने पर तालिका की प्राथमिक कुंजी के रूप में काम कर सकता है।

उदाहरण के लिए, अतिरिक्त वर्ग का कार्यान्वयन कोड इस तरह दिखना चाहिए:

@Entity
@Table(name = "USER_SERVICES")
public class UserService{

    // example of auto-generated ID
    @Id
    @Column(name = "USER_SERVICES_ID", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long userServiceID;



    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "USER_ID")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "SERVICE_ID")
    private Service service;



    // example of extra column
    @Column(name="VISIBILITY")    
    private boolean visibility;



    public long getUserServiceID() {
        return userServiceID;
    }


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Service getService() {
        return service;
    }

    public void setService(Service service) {
        this.service = service;
    }

    public boolean getVisibility() {
        return visibility;
    }

    public void setVisibility(boolean visibility) {
        this.visibility = visibility;
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.