জেপিএ: একই সত্তা টাইপের এক থেকে একাধিক সম্পর্ক কীভাবে থাকতে পারে


102

একটি সত্তা ক্লাস "এ" আছে। ক্লাস এ এর ​​একই ধরণের "এ" এর শিশু থাকতে পারে। এছাড়াও "এ" এর যদি এটি সন্তান হয় তবে তার পিতামাতাকে ধরে রাখা উচিত।

এটা কি সম্ভব? যদি তা হয় তবে কীভাবে আমি সত্ত্বার শ্রেণিতে সম্পর্কের মানচিত্র করব? ["এ" এর একটি আইডি কলাম রয়েছে]]

উত্তর:


173

হ্যাঁ, এটি সম্ভব। এটি স্ট্যান্ডার্ড দ্বিদ্বিতীয় @ManyToOne/ @OneToManyসম্পর্কের একটি বিশেষ ক্ষেত্রে । এটি বিশেষ কারণ সম্পর্কের প্রতিটি প্রান্তে সত্তা একই। সাধারণ কেসটি জেপিএ ২.০ অনুচ্ছেদের ২.১০.২ বিভাগে বিশদে রয়েছে ।

এখানে একটি কাজের উদাহরণ। প্রথম, সত্তা শ্রেণি A:

@Entity
public class A implements Serializable {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private Long id;
    @ManyToOne
    private A parent;
    @OneToMany(mappedBy="parent")
    private Collection<A> children;

    // Getters, Setters, serialVersionUID, etc...
}

এখানে একটি রুক্ষ main()পদ্ধতি যা এই জাতীয় তিনটি সত্তাকে স্থায়ী করে:

public static void main(String[] args) {

    EntityManager em = ... // from EntityManagerFactory, injection, etc.

    em.getTransaction().begin();

    A parent   = new A();
    A son      = new A();
    A daughter = new A();

    son.setParent(parent);
    daughter.setParent(parent);
    parent.setChildren(Arrays.asList(son, daughter));

    em.persist(parent);
    em.persist(son);
    em.persist(daughter);

    em.getTransaction().commit();
}

এক্ষেত্রে লেনদেনের প্রতিশ্রুতি দেওয়ার আগে তিনটি সত্তা উদাহরণ থাকতে হবে। আমি যদি পিতা-মাতার সন্তানের সম্পর্কের গ্রাফের কোনও একটি সত্তাকে অবিচল রাখতে ব্যর্থ হই, তবে তার ব্যতিক্রমও ছুঁড়ে দেওয়া হবে commit()। ইক্লিপসেলিংকে, RollbackExceptionএটি অসঙ্গতিটির বিবরণ দেয় is

এই আচরণ মাধ্যমে কনফিগার করা যাবে cascadeউপর অ্যাট্রিবিউট Aএর @OneToManyএবং @ManyToOneটীকা। উদাহরণস্বরূপ, যদি আমি cascade=CascadeType.ALLএই দুটি টীকাকে সেট করে রাখি তবে আমি নিরাপদে সত্তার একটির চালিয়ে যেতে এবং অন্যকে উপেক্ষা করতে পারি। বলুন আমি parentআমার লেনদেনে জেদ করেছিলাম জেপিএ বাস্তবায়ন parentএর childrenসম্পত্তি চিহ্নিত করেছে কারণ এটি চিহ্নিত রয়েছে CascadeType.ALL। জেপিএ বাস্তবায়ন খুঁজে পায় sonএবং daughterসেখানে। এটি তখন উভয় বাচ্চাকে আমার পক্ষে চালিয়ে যায়, যদিও আমি স্পষ্টভাবে এটির জন্য অনুরোধ করি নি।

আরও একটি নোট। দ্বিপাক্ষিক সম্পর্কের উভয় পক্ষকে আপডেট করা সর্বদা প্রোগ্রামারের দায়িত্ব। অন্য কথায়, আমি যখনই কোনও সন্তানের পিতামাতার সাথে যুক্ত করি তখন অবশ্যই আমাকে সেই অনুযায়ী সন্তানের পিতামাতার সম্পত্তি আপডেট করতে হবে। দ্বি নির্দেশমূলক সম্পর্কের কেবলমাত্র এক পক্ষ আপডেট করা জেপিএ-এর অধীনে ত্রুটি। সম্পর্কের উভয় দিক সর্বদা আপডেট করুন। এটি জেপিএ ২.০ অনুচ্ছেদের ৪২ পৃষ্ঠায় নির্বিঘ্নে লেখা হয়েছে:

নোট করুন যে এটি সেই অ্যাপ্লিকেশন যা রানটাইম সম্পর্কের ধারাবাহিকতা বজায় রাখার জন্য দায়িত্ব বহন করে - উদাহরণস্বরূপ, দ্বিমুখী সম্পর্কের "এক" এবং "অনেক" পক্ষ একে অপরের সাথে সামঞ্জস্যপূর্ণ হওয়ার জন্য বীমাটি প্রয়োগ করার সময় অ্যাপ্লিকেশন রানটাইমের সময় সম্পর্কের আপডেট করে ।


বিস্তারিত ব্যাখ্যার জন্য আপনাকে অনেক ধন্যবাদ! উদাহরণটি উদাহরণস্বরূপ এবং প্রথম রানে কাজ করেছে worked
সানজায়ভ

@ সান্নিজ খুশি আপনার প্রকল্প (গুলি) এর জন্য শুভকামনা।
ড্যান লরোক

উপ বিষয়শ্রেণীতে শ্রেণি সত্তা তৈরি করার আগে এটি এই সমস্যাটি পূরণ করেছিল। এটি উপকারী!
ট্রুং হা

@ ড্যানালোক সম্ভবত সম্ভবত আমি ভুল বোঝাবুঝি করছি (বা কোনও সত্তা ম্যাপিংয়ের ত্রুটি রয়েছে) তবে আমি অপ্রত্যাশিত আচরণ দেখছি। ব্যবহারকারী এবং ঠিকানার মধ্যে আমার একের সাথে একাধিক সম্পর্ক রয়েছে। যখন কোনও বিদ্যমান ব্যবহারকারী কোনও ঠিকানা যুক্ত করেন, তখন আমি ব্যবহারকারী এবং ঠিকানা উভয়কে আপডেট করার জন্য আপনার পরামর্শ অনুসরণ করেছিলাম (এবং উভয়টিতে 'সংরক্ষণ করুন')। তবে এর ফলে আমার ঠিকানা সারণীতে একটি সদৃশ সারি sertedোকানো হয়েছিল। এটি কি কারণ আমি ব্যবহারকারীর ঠিকানা ক্ষেত্রে আমার ক্যাসকেডটাইপটি ভুল কনফিগার করেছি?
অ্যালেক্স

@ ড্যানালারোক এই সম্পর্কটিকে একমুখী হিসাবে চিহ্নিত করা সম্ভব কি ??
আলী আরদা ওরহান

8

আমার জন্য কৌশলটি ছিল বহু থেকে বহু সম্পর্ক ব্যবহার করা relationship মনে করুন যে আপনার সত্তা A একটি বিভাগ যা উপ-বিভাগ থাকতে পারে। তারপরে (অপ্রাসঙ্গিক বিশদটি বাদ দেওয়া):

@Entity
@Table(name = "DIVISION")
@EntityListeners( { HierarchyListener.class })
public class Division implements IHierarchyElement {

  private Long id;

  @Id
  @Column(name = "DIV_ID")
  public Long getId() {
        return id;
  }
  ...
  private Division parent;
  private List<Division> subDivisions = new ArrayList<Division>();
  ...
  @ManyToOne
  @JoinColumn(name = "DIV_PARENT_ID")
  public Division getParent() {
        return parent;
  }

  @ManyToMany
  @JoinTable(name = "DIVISION", joinColumns = { @JoinColumn(name = "DIV_PARENT_ID") }, inverseJoinColumns = { @JoinColumn(name = "DIV_ID") })
  public List<Division> getSubDivisions() {
        return subDivisions;
  }
...
}

যেহেতু শ্রেণিবদ্ধ কাঠামোর চারপাশে আমার কিছু বিস্তৃত ব্যবসার যুক্তি ছিল এবং এটি সমর্থন করার জন্য জেপিএ (রিলেশনাল মডেলের উপর ভিত্তি করে) খুব দুর্বল আমি ইন্টারফেস IHierarchyElementএবং সত্তা শ্রোতার সাথে পরিচয় করিয়ে দিয়েছি HierarchyListener:

public interface IHierarchyElement {

    public String getNodeId();

    public IHierarchyElement getParent();

    public Short getLevel();

    public void setLevel(Short level);

    public IHierarchyElement getTop();

    public void setTop(IHierarchyElement top);

    public String getTreePath();

    public void setTreePath(String theTreePath);
}


public class HierarchyListener {

    @PrePersist
    @PreUpdate
    public void setHierarchyAttributes(IHierarchyElement entity) {
        final IHierarchyElement parent = entity.getParent();

        // set level
        if (parent == null) {
            entity.setLevel((short) 0);
        } else {
            if (parent.getLevel() == null) {
                throw new PersistenceException("Parent entity must have level defined");
            }
            if (parent.getLevel() == Short.MAX_VALUE) {
                throw new PersistenceException("Maximum number of hierarchy levels reached - please restrict use of parent/level relationship for "
                        + entity.getClass());
            }
            entity.setLevel(Short.valueOf((short) (parent.getLevel().intValue() + 1)));
        }

        // set top
        if (parent == null) {
            entity.setTop(entity);
        } else {
            if (parent.getTop() == null) {
                throw new PersistenceException("Parent entity must have top defined");
            }
            entity.setTop(parent.getTop());
        }

        // set tree path
        try {
            if (parent != null) {
                String parentTreePath = StringUtils.isNotBlank(parent.getTreePath()) ? parent.getTreePath() : "";
                entity.setTreePath(parentTreePath + parent.getNodeId() + ".");
            } else {
                entity.setTreePath(null);
            }
        } catch (UnsupportedOperationException uoe) {
            LOGGER.warn(uoe);
        }
    }

}

4
স্ব-রেফারেন্সিং গুণাবলী সহ @ ম্যানিটোম্যানি (...) এর পরিবর্তে সরল @OneToMany (ম্যাপডবাই = "DIV_PARENT_ID") ব্যবহার করবেন না কেন? এর মতো টেবিল এবং কলামের নাম পুনরায় টাইপ করা DRY কে লঙ্ঘন করে। সম্ভবত এর কারণ আছে তবে আমি এটি দেখতে পাচ্ছি না। এছাড়াও, এন্টিলিস্টনার উদাহরণটি ঝরঝরে হলেও অ-বহনযোগ্য, ধরে Topনেওয়া একটি সম্পর্ক। জেপিএ ২.০ অনুচ্ছেদের পৃষ্ঠা 93, সত্তা শ্রোতাদের এবং কলব্যাক পদ্ধতিগুলি: "সাধারণভাবে, একটি পোর্টেবল অ্যাপ্লিকেশনটির জীবনকালীন পদ্ধতিতে সত্ত্বা ব্যবস্থাপক বা ক্যোয়ারী অপারেশনগুলি গ্রহণ করা উচিত নয়, অন্য সত্তার দৃষ্টান্তগুলিতে অ্যাক্সেস করা বা সম্পর্ক পরিবর্তন করা উচিত নয়"। ঠিক? আমি বন্ধ থাকলে আমাকে জানাবেন।
ড্যান লরোক

আমার সমাধানটি জেপিএ 1.0 ব্যবহার করে 3 বছরের পুরানো। আমি এটিকে প্রযোজনা কোড থেকে অপরিবর্তিত রেখেছি। আমি নিশ্চিত যে আমি কিছু কলামের নাম বের করতে পেরেছিলাম তবে এটি পয়েন্ট ছিল না। আপনার উত্তরটি হুবহু এবং সরল করে তোলে, নিশ্চিত না যে আমি তখন কেন বহু লোককে পিছনে ব্যবহার করেছি - তবে এটি কার্যকর হয় এবং আমি আত্মবিশ্বাসী যে আরও জটিল সমাধানের কারণ ছিল there যদিও, আমাকে এখনই এটি আবার দেখতে হবে।
টপচেফ

হ্যাঁ, শীর্ষটি একটি স্ব-রেফারেন্স, অতএব একটি সম্পর্ক। কড়া কথায় বলতে গেলে, আমি এটিকে সংশোধন করি না - কেবল আরম্ভ করুন। এছাড়াও, এটি একমুখী হয় সুতরাং অন্যদিকে কোনও নির্ভরতা নেই, এটি স্ব ছাড়াও অন্যান্য সত্তাগুলিকে উল্লেখ করে না। আপনার উদ্ধৃতি অনুযায়ী প্রতিবেদনটি "সাধারণভাবে" রয়েছে যার অর্থ এটি কঠোর সংজ্ঞা নয়। আমি বিশ্বাস করি যে এক্ষেত্রে খুব কম পোর্টেবিলিটি ঝুঁকি যদি থাকে তবে।
topchef
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.