জেপিএতে (এবং একই সাথে টেবিল সারিগুলিতে যোগ হওয়া) মুনটোমনি সম্পর্কের সাথে সত্তা কীভাবে সরিয়ে নেওয়া যায়?


91

ধরা যাক আমার দুটি সত্তা রয়েছে: গ্রুপ এবং ব্যবহারকারী। প্রতিটি ব্যবহারকারী অনেক গ্রুপের সদস্য হতে পারে এবং প্রতিটি গ্রুপে অনেক ব্যবহারকারী থাকতে পারে।

@Entity
public class User {
    @ManyToMany
    Set<Group> groups;
    //...
}

@Entity
public class Group {
    @ManyToMany(mappedBy="groups")
    Set<User> users;
    //...
}

এখন আমি একটি গোষ্ঠী অপসারণ করতে চাই (যাক এর অনেক সদস্য রয়েছে বলে নিই)

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

সুতরাং আমি কীভাবে এই ক্ষেত্রে একটি গোষ্ঠী অপসারণ করতে পারি?

আমি কেবলমাত্র গ্রুপটিতে উপস্থিত সমস্ত ব্যবহারকারীকে লোড করা, তারপরে প্রতিটি ব্যবহারকারীর জন্য তার গোষ্ঠী থেকে বর্তমান গ্রুপটি সরিয়ে এবং ব্যবহারকারীকে আপডেট করা। তবে গোষ্ঠী থেকে প্রতিটি ব্যবহারকারীর কাছে এই গ্রুপটি মুছতে সক্ষম হবার জন্য আপডেট () আপডেট করা আমার কাছে হাস্যকর বলে মনে হচ্ছে।

উত্তর:


86
  • সম্পর্কের মালিকানা নির্ধারণ করা হয় যেখানে আপনি টীকায় 'ম্যাপডবাই' গুণটি রেখেছেন। আপনি যে সত্তা 'ম্যাপডবাই' রেখেছেন সেটি হ'ল সেই মালিক নয়। উভয় পক্ষের মালিক হওয়ার কোনও সুযোগ নেই। আপনার যদি কোনও 'মুছুন ব্যবহারকারী' ব্যবহার-কেস না থাকে তবে আপনি কেবল মালিকানা Groupসত্তায় সরিয়ে নিতে পারেন , যেমন বর্তমানে Userমালিক।
  • অন্যদিকে, আপনি এটি সম্পর্কে জিজ্ঞাসা করছেন না, তবে একটি জিনিস জেনে রাখা উচিত। groupsএবং usersএকে অপরের সাথে মিলিত হয় না। আমি বলতে চাইছি, গ্রুপ 1. ব্যবহারকারীদের থেকে ইউজার 1 উদাহরণটি মোছার পরে, ব্যবহারকারীর 1 গোষ্ঠী সংগ্রহগুলি স্বয়ংক্রিয়ভাবে পরিবর্তিত হবে না (যা আমার জন্য বেশ অবাক করার মতো),
  • সব মিলিয়ে, আমি আপনাকে পরামর্শ দিচ্ছি যে কে সিদ্ধান্ত নেবেন মালিক। যাক Userএর মালিক। তারপরে কোনও ব্যবহারকারীকে মুছে ফেলার সময় সম্পর্ক ব্যবহারকারী-গোষ্ঠীটি স্বয়ংক্রিয়ভাবে আপডেট হবে। তবে কোনও গোষ্ঠী মোছার সময় আপনাকে নিজের মতো করে এই সম্পর্কটি মোছার যত্ন নিতে হবে:

entityManager.remove(group)
for (User user : group.users) {
     user.groups.remove(group);
}
...
// then merge() and flush()

Thnx! আমার একই সমস্যা ছিল এবং আপনার সমাধান এটি সমাধান করেছে। তবে এই সমস্যাটি সমাধানের আর কোনও উপায় আছে কিনা তা অবশ্যই আমার জানা উচিত। এটি একটি ভয়াবহ কোড উত্পাদন করে। কেন এটি এম। রেম (সত্তা) হতে পারে না এবং এটিই কি?
রয়ী ফ্রিফিল্ড

4
পর্দার আড়ালে এটি কি অনুকূলিত হয়েছে? আমি পুরো ডেটাসেটটি জিজ্ঞাসা করতে চাই না
সিড

4
এটি সত্যিই খারাপ দৃষ্টিভঙ্গি, যদি আপনার সেই দলে কয়েক হাজার ব্যবহারকারী থাকে?
সের্গেই সোকোলেঙ্কো

4
এটি সম্পর্কের টেবিলটি আপডেট করে না, সম্পর্ক সারণীতে এই সম্পর্ক সম্পর্কে সারিগুলি এখনও অবধি রয়েছে। আমি পরীক্ষা করিনি তবে এটি সম্ভাব্য সমস্যা তৈরি করতে পারে।
Saygın Doğu

লগের জন্য সার্জিইসোকোলেঙ্কো কোনও ডাটাবেস প্রশ্নই কার্যকর করা হয় না। লেনদেনের ক্রিয়াকলাপটি বাকি থাকার পরে তাদের সকলকে বাচানো হয়।
কিলভেস

42

নিম্নলিখিত আমার জন্য কাজ করে। সম্পর্কের মালিক নয় এমন সত্তায় নিম্নলিখিত পদ্ধতিটি যুক্ত করুন (গ্রুপ)

@PreRemove
private void removeGroupsFromUsers() {
    for (User u : users) {
        u.getGroups().remove(this);
    }
}

মনে রাখবেন যে এটি কাজ করার জন্য, গোষ্ঠীর ব্যবহারকারীদের একটি আপডেট তালিকা থাকতে হবে (যা স্বয়ংক্রিয়ভাবে করা হয় না)। সুতরাং প্রতিবার আপনি ব্যবহারকারী সত্তায় গ্রুপ তালিকায় একটি গ্রুপ যুক্ত করার পরে, আপনাকে গ্রুপ সত্তায় ব্যবহারকারী তালিকায় কোনও ব্যবহারকারী যুক্ত করা উচিত।


4
ক্যাসকেড = ক্যাসকেডটাইপ.এল আপনি যখন এই সমাধানটি ব্যবহার করতে চান তখন সেট করা উচিত নয়। অন্যথায় এটি নিখুঁত কাজ করে!
ltsstar

@ দামিয়ান হাই আমি আপনার সমাধানটি ব্যবহার করেছি, তবে আমার মনে হয়েছে একটি ত্রুটিপূর্ণ যুগোপযোগী মডেলফিকেশন আমি মনে করি কারণ আপনি উল্লেখ করেছেন কারণ গ্রুপটির ব্যবহারকারীর একটি আপডেট তালিকা থাকতে হবে। কারণ আমি যদি ব্যবহারকারীকে একাধিক গোষ্ঠী যুক্ত করি তবে আমি এই ব্যতিক্রমটি পাই ...
আদনান আবদুল খালিক

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

27

আমি একটি সম্ভাব্য সমাধান খুঁজে পেয়েছি, তবে ... আমি জানি না এটি ভাল সমাধান কিনা।

@Entity
public class Role extends Identifiable {

    @ManyToMany(cascade ={CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name="Role_Permission",
            joinColumns=@JoinColumn(name="Role_id"),
            inverseJoinColumns=@JoinColumn(name="Permission_id")
        )
    public List<Permission> getPermissions() {
        return permissions;
    }

    public void setPermissions(List<Permission> permissions) {
        this.permissions = permissions;
    }
}

@Entity
public class Permission extends Identifiable {

    @ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(name="Role_Permission",
            joinColumns=@JoinColumn(name="Permission_id"),
            inverseJoinColumns=@JoinColumn(name="Role_id")
        )
    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

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

ধন্যবাদ!

উপরের কোড সম্পর্কিত অন্য পোস্ট সম্পর্কিত from


সংগ্রহ রিফ্রেশ সমস্যা?
জেলি

12
এটি সঠিক নয়। দ্বি নির্দেশমূলক মুনটোম্যানির সম্পর্কের এক এবং একমাত্র মালিকের দিক থাকা উচিত। এই সমাধানটি উভয় পক্ষকেই মালিক হিসাবে তৈরি করছে এবং পরিণামে সদৃশ রেকর্ডের ফলস্বরূপ। সদৃশ রেকর্ড এড়ানোর জন্য, তালিকাগুলির পরিবর্তে সেটগুলি অবশ্যই ব্যবহার করা উচিত। তবে, সেট ব্যবহার করা এমন কোনও কাজ করার জন্য কেবলমাত্র এক প্রস্তাব যা সুপারিশ করা হয় না।
এল। হল্যান্ডা

4
তাহলে এ জাতীয় সাধারণ পরিস্থিতিতে সবচেয়ে ভাল অনুশীলন কী?
সালুটনমন্ডো

8

জেপিএ / হাইবারনেট সমাধানগুলির বিকল্প হিসাবে: আপনি আপনার যোগদানের টেবিলে আপনার ফরজেন কী এর ডাটাবেস সংজ্ঞাতে ক্যাসকেড ডিলেট ডিভাইসটি ব্যবহার করতে পারেন, যেমন (ওরাকল সিনট্যাক্স):

CONSTRAINT fk_to_group
     FOREIGN KEY (group_id)
     REFERENCES group (id)
     ON DELETE CASCADE

আপনি গোষ্ঠীটি মুছে ফেলার সময় ডিবিএমএস স্বয়ংক্রিয়ভাবে সেই সারিটি সরিয়ে দেয় যা গোষ্ঠীটির দিকে নির্দেশ করে। এবং ডিলিটটি হাইবারনেট / জেপিএ, জেডিবিসি থেকে নিজেই ডিবিতে বা অন্য কোনও উপায়ে তৈরি করা হয়েছে কিনা তা এটি কাজ করে।

ক্যাসকেড মোছার বৈশিষ্ট্যটি সমস্ত বড় ডিবিএমএস (ওরাকল, মাইএসকিউএল, এসকিউএল সার্ভার, পোস্টগ্রিসকিউএল) দ্বারা সমর্থিত।


3

এর মূল্য কী, তার জন্য আমি EclipseLink 2.3.2.v20111125-r10461 ব্যবহার করছি এবং আমার যদি @ManyToMany একমুখী সম্পর্ক থাকে তবে আমি আপনার বর্ণিত সমস্যাটি পর্যবেক্ষণ করি। তবে, আমি যদি এটি দ্বি-দিকনির্দেশক @ ম্যানি টোমনি সম্পর্ক হিসাবে পরিবর্তন করি তবে আমি অ-মালিকানাধীন দিক থেকে কোনও সত্তা মুছতে সক্ষম হয়েছি এবং জয়ন সারণি যথাযথভাবে আপডেট করা হয়েছে। এটি কোনও ক্যাসকেড বৈশিষ্ট্য ব্যবহার ছাড়াই is


2

এটি আমার পক্ষে কাজ করে:

@Transactional
public void remove(Integer groupId) {
    Group group = groupRepository.findOne(groupId);
    group.getUsers().removeAll(group.getUsers());

    // Other business logic

    groupRepository.delete(group);
}

এছাড়াও, @ ট্রানজেকশনাল (org.springframework.transaction.annotation.Annotation.Transactional) পদ্ধতিটি চিহ্নিত করুন, এটি এক সেশনে পুরো প্রক্রিয়াটি করবে, কিছু সময় সাশ্রয় করবে।


1

এটি একটি ভাল সমাধান। সবচেয়ে ভাল অংশটি এসকিউএল দিকে - যে কোনও স্তরে সূক্ষ্ম সুরকরণ সহজ।

প্রয়োজনীয় বিদেশী কেইওয়াইয়ের জন্য মুছে ফেলার জন্য আমি মাইএসকিএল এবং মাইএসকিএল ওয়ার্কবেঞ্চকে ক্যাসকেডে ব্যবহার করেছি।

ALTER TABLE schema.joined_table 
ADD CONSTRAINT UniqueKey
FOREIGN KEY (key2)
REFERENCES schema.table1 (id)
ON DELETE CASCADE;

তাই আপনাকে স্বাগতম। অনুগ্রহ করে আপনার বিন্যাস এবং প্রমাণ পড়া উন্নত করতে এই মধ্যে একটি মুহূর্ত এবং কটাক্ষপাত: stackoverflow.com/help/how-to-ask
petezurich

1

এটিই আমি শেষ করেছিলাম। আশা করি কারওর পক্ষে এটি কাজে লাগবে।

@Transactional
public void deleteGroup(Long groupId) {
    Group group = groupRepository.findById(groupId).orElseThrow();
    group.getUsers().forEach(u -> u.getGroups().remove(group));
    userRepository.saveAll(group.getUsers());
    groupRepository.delete(group);
}

0

আমার ক্ষেত্রে, আমি ম্যাপডবাইটি মোছা করেছি এবং এর মতো টেবিলগুলিতে যোগদান করেছি:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "user_group", joinColumns = {
        @JoinColumn(name = "user", referencedColumnName = "user_id")
}, inverseJoinColumns = {
        @JoinColumn(name = "group", referencedColumnName = "group_id")
})
private List<User> users;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonIgnore
private List<Group> groups;

4
বহু-বহুতে ক্যাসকেডটাইপ.এল ব্যবহার করবেন না। মোছার পরে এটি A রেকর্ডের সাথে সম্পর্কিত সমস্ত বি রেকর্ড মুছে দেয়। এবং বি রেকর্ডগুলি সম্পর্কিত সমস্ত রেকর্ড মুছে দেয়। ইত্যাদি। বড় নং-না
জোশিয়ার

0

এটি একই ধরণের বিষয়ে আমার পক্ষে কাজ করে যেখানে আমি উল্লেখের কারণে ব্যবহারকারীকে মুছতে ব্যর্থ হয়েছি। ধন্যবাদ

@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST,CascadeType.REFRESH})
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.