পার্সেন্টিওবজেক্টএক্সেপশন: বিচ্ছিন্ন সত্তা জেপিএ এবং হাইবারনেট দ্বারা নিক্ষেপ করা চালিয়ে যেতে পেরেছে


237

আমার কাছে একটি জেপিএ-অবিচলিত অবজেক্ট মডেল রয়েছে যার মধ্যে একাধিক থেকে এক সম্পর্ক রয়েছে: একটিতে Accountঅনেকগুলি রয়েছে Transactions। ক একটি Transactionআছে Account

কোডটির একটি স্নিপেট এখানে দেওয়া হয়েছে:

@Entity
public class Transaction {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
    private Account fromAccount;
....

@Entity
public class Account {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")
    private Set<Transaction> transactions;

আমি একটি Accountঅবজেক্ট তৈরি করতে , এতে লেনদেন যুক্ত করতে এবং Accountসঠিকভাবে অবজেক্টটি অবিরত রাখতে সক্ষম । তবে, আমি যখন ইতিমধ্যে বিদ্যমান বিদ্যমান অ্যাকাউন্ট ব্যবহার করে এবং লেনদেন চালিয়ে যাওয়ার সময়ে লেনদেন তৈরি করি তখন আমি একটি ব্যতিক্রম পাই:

এর দ্বারা তৈরি: org.hibernate.PersistanceObjectException: বিচ্ছিন্ন সত্তা অস্তিত্ব বজায় রাখতে পেরে: com.paulsanwald.Acount at org.hibernate.event.intern.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:141)

সুতরাং, আমি একটি জিদ সক্ষম Accountএকটি লেনদেন নয় যে যে লেনদেন রয়েছে, কিন্তু Account। আমি ভেবেছিলাম এটি Accountসম্ভবত কারণ সংযুক্ত করা হয়নি, তবে এই কোডটি এখনও আমাকে একই ব্যতিক্রম দেয়:

if (account.getId()!=null) {
    account = entityManager.merge(account);
}
Transaction transaction = new Transaction(account,"other stuff");
 // the below fails with a "detached entity" message. why?
entityManager.persist(transaction);

Transactionইতিমধ্যে স্থায়ী Accountঅবজেক্টের সাথে যুক্ত একটিকে কীভাবে সঠিকভাবে সংরক্ষণ করতে পারি ?


15
আমার ক্ষেত্রে, আমি এমন একটি সত্তার আইডি সেট করেছিলাম যা সত্তা পরিচালককে ব্যবহার করে চালিয়ে যাওয়ার চেষ্টা করছিলাম। আমি যখন আইডিটির জন্য সেটারটি সরিয়েছি, এটি ঠিকঠাক কাজ শুরু করে।
রশি শাহ

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

উত্তর:


129

এটি একটি সাধারণ দ্বিপাক্ষিক সামঞ্জস্যতা সমস্যা। এটি এই লিঙ্কের পাশাপাশি এই লিঙ্কটিতেও বেশ আলোচিত

পূর্ববর্তী 2 লিঙ্কগুলির নিবন্ধ অনুসারে আপনাকে দ্বিপাক্ষিক সম্পর্কের উভয় পক্ষে আপনার সেটারগুলি ঠিক করতে হবে। এক পক্ষের উদাহরণস্বরূপ এই লিঙ্কটিতে।

বহু পক্ষের জন্য উদাহরণস্বরূপ সেটারটি এই লিঙ্কটিতে রয়েছে।

আপনার সেটটারগুলি সংশোধন করার পরে আপনি সত্তা অ্যাক্সেস প্রকারটিকে "সম্পত্তি" হিসাবে ঘোষণা করতে চান। "সম্পত্তি" অ্যাক্সেসের ধরণের ঘোষণার সেরা অনুশীলন হ'ল সমস্ত মন্তব্যগুলি সদস্যের সম্পত্তি থেকে সংশ্লিষ্ট প্রাপ্তদের কাছে স্থানান্তরিত করা। সতর্কতার একটি বড় কথা সত্তা শ্রেণীর মধ্যে "ক্ষেত্র" এবং "সম্পত্তি" অ্যাক্সেসের ধরণের মিশ্রণ নয় অন্যথায় আচরণটি JSR-317 স্পেসিফিকেশন দ্বারা আবশ্যক নয়।


2
পিএস: @ আইড টীকাটি হ'ল হাইবারনেট অ্যাক্সেসের ধরণ সনাক্ত করতে ব্যবহার করে।
দিয়েগো প্লেন্টজ

2
ব্যতিক্রমটি হ'ল: detached entity passed to persistধারাবাহিকতার উন্নতি কেন এটি কার্যকর করে? ঠিক আছে, ধারাবাহিকতা মেরামত করা হয়েছিল তবে অবজেক্টটি এখনও পৃথক।
গিলগ্যামেজ

1
@ সাম, আপনার ব্যাখ্যার জন্য অনেক ধন্যবাদ। কিন্তু, আমি এখনও বুঝতে পারি না। আমি দেখতে পাচ্ছি যে 'বিশেষ' সেটার ছাড়াই দ্বি-দিকীয় সম্পর্ক সন্তুষ্ট হয় না। তবে, আমি দেখতে পাচ্ছি না কেন বস্তুটি আলাদা করা হয়েছিল।
গিলগেমস

28
দয়া করে এমন কোনও লিঙ্ক পোস্ট করবেন না যা সম্পূর্ণ লিঙ্কগুলির সাথে উত্তর দেয়।
এল ম্যাক

6
এই উত্তরটি কীভাবে প্রশ্নের সাথে সম্পর্কিত তা দেখতে পাচ্ছেন না?
ইউজেন লাবুন

270

সমাধান, সহজ শুধু ব্যবহার CascadeType.MERGEপরিবর্তে CascadeType.PERSISTবা CascadeType.ALL

আমারও একই সমস্যা ছিল এবং CascadeType.MERGEআমার পক্ষে কাজ করেছি।

আমি আশা করি আপনার বাছাই হয়েছে


5
আশ্চর্যের বিষয় যে সে আমার পক্ষেও কাজ করেছিল। ক্যাসকেডটাইপ.এল সব অন্যান্য ক্যাসকেড ধরণের অন্তর্ভুক্ত করার কারণে এটি কোনও অর্থবোধ করে না ... ডাব্লুটিএফ? আমার কাছে বসন্ত 4.0.০.৪, বসন্তের ডেটা জেপা ১.৮.০ এবং হাইবারনেট ৪. এক্স আছে .. কারও কি কোনও ধারণা আছে যে সমস্ত কাজ করে না, তবে মার্জ করে?
ভাদিম কিরিলচুক

22
@ ভাদিমকিরিলচুক এটি আমার পক্ষেও কাজ করেছে এবং এটি মোটামুটি অর্থপূর্ণ। যেহেতু লেনদেনটি পার্সট করা থাকে তাই এটি অ্যাকাউন্টেও পার্সটিস্ট করার চেষ্টা করে এবং অ্যাকাউন্টটি ইতিমধ্যে ডিবিতে থাকায় এটি কাজ করে না। তবে ক্যাসকেডটাইপ.মার্গের সাথে অ্যাকাউন্টটি স্বয়ংক্রিয়ভাবে পরিবর্তিত হয়ে যায়।
গানস্লিংগার

4
আপনি লেনদেন ব্যবহার না করলে এটি ঘটতে পারে।
ল্যানোক্সিক্স

1
অন্য একটি সমাধান: ইতিমধ্যে স্থির অবজেক্টটি
sertোকানোর

3
আপনি মানুষ ধন্যবাদ. রেফারেন্স কীটি বাতিল না করার জন্য আপনার যদি সীমাবদ্ধতা থাকে তবে অবিচলিত অবজেক্টটি প্রবেশ করা এড়ানো সম্ভব নয়। সুতরাং এটিই একমাত্র সমাধান। আবার আপনাকে ধন্যবাদ.
মকাকাসি

22

শিশু সত্তা থেকে ক্যাসকেডিং সরানTransaction , এটি ঠিক হওয়া উচিত:

@Entity class Transaction {
    @ManyToOne // no cascading here!
    private Account account;
}

( FetchType.EAGERঅপসারণের পাশাপাশি এটি ডিফল্টও হতে পারে @ManyToOne)

এখানেই শেষ!

কেন? শিশু সত্তার উপর "ক্যাসকেড সমস্ত" বলার মাধ্যমে Transactionআপনার প্রয়োজন প্রতিটি ডিবি ক্রিয়াকলাপ প্যারেন্ট সত্তায় প্রচারিত হয় Account। তারপর আপনি যদি persist(transaction), persist(account)সেইসাথে প্রার্থনা করা হবে না।

তবে কেবলমাত্র ক্ষণস্থায়ী (নতুন) সত্তা persist( Transactionএই ক্ষেত্রে) এ পাস হতে পারে । বিচ্ছিন্ন (বা অন্যান্য অস্থায়ী অবস্থা )গুলি নাও পারে ( Accountএই ক্ষেত্রে এটি ইতিমধ্যে ডিবিতে রয়েছে)।

অতএব আপনি ব্যতিক্রম পেতে "বিচ্ছিন্ন সত্তা জিদ প্রেরণ"Accountসত্তা বোঝানো হয়! Transactionআপনি কল না persist


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

অনুমান করুন যে আপনি যদি remove(transaction)এখনও @ ম্যানটিওওনে "ক্যাসকেড অল" রেখেছেন তবে কি হবে ? account(BTW, অন্যান্য সমস্ত লেনদেন সঙ্গে!) ডিবি থেকে পাশাপাশি মুছে ফেলা হবে। কিন্তু এটি আপনার উদ্দেশ্য ছিল না, তাই না?


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

যদি আমরা কিছু পাস করতে না পারি তবে এটি সমস্ত ক্ষেত্রে কী ডিফল্ট মান take
ধওয়ানিল প্যাটেল

15

মার্জ ব্যবহার করা ঝুঁকিপূর্ণ এবং কৃপণ, সুতরাং এটি আপনার ক্ষেত্রে একটি নোংরা কাজ work আপনাকে কমপক্ষে মনে রাখতে হবে যে আপনি যখন সত্তার কোনও জিনিসটি মার্জ করার জন্য পাস করেন তখন এটি লেনদেনের সাথে যুক্ত হওয়া বন্ধ করে দেয় এবং পরিবর্তে একটি নতুন, এখন-সংযুক্ত সত্তা ফিরিয়ে দেওয়া হয়। এর অর্থ হ'ল কারও কাছে যদি পুরোনো সত্তার অবধি এখনও তাদের দখলে থাকে তবে এতে পরিবর্তনগুলি নীরবে উপেক্ষা করা হবে এবং প্রতিশ্রুতিবদ্ধ হয়ে ফেলে দেওয়া হবে।

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

ধারক-পরিচালিত লেনদেন ব্যবহার করে এটি দেখতে এমন কিছু দেখাচ্ছে। মনে রাখবেন: এটি ধরে নেয় পদ্ধতিটি একটি সেশন বিনের মধ্যে এবং স্থানীয় বা দূরবর্তী ইন্টারফেসের মাধ্যমে কল করা হয়।

@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void storeAccount(Account account) {
    ...

    if (account.getId()!=null) {
        account = entityManager.merge(account);
    }

    Transaction transaction = new Transaction(account,"other stuff");

    entityManager.persist(account);
}

আমি একই সমস্যার মুখোমুখি হচ্ছি।, আমি @Transaction(readonly=false)সার্ভিস লেয়ারে এটি ব্যবহার করেছি ।, এখনও একই সমস্যা
পাচ্ছি

আমি বলতে পারি না যে জিনিসগুলি কেন এইভাবে কাজ করে তবে আমি অবিচ্ছিন্ন পদ্ধতিটি রাখি এবং লেনদেনের টীকাতে একত্রে অ্যান্টি ম্যাপিংকে দেখানো আমার সমস্যাটিকে সংশোধন করে তাই ধন্যবাদ।
ডেড্রন

এটি প্রকৃতপক্ষে সবচেয়ে আপোভোটেড এর চেয়ে ভাল সমাধান।
আলেকসেই মাইদে

13

সম্ভবত accountএক্ষেত্রে আপনি একত্রীকরণ যুক্তি ব্যবহার করে আপনার বস্তুটি পেয়েছেন এবং persistনতুন অবজেক্ট অবিরত রাখতে ব্যবহৃত হয় এবং হায়ারার্কির যদি ইতিমধ্যে স্থায়ী অবজেক্ট থাকে তবে এটি অভিযোগ করবে। saveOrUpdateপরিবর্তে, আপনার এই জাতীয় ক্ষেত্রে ব্যবহার করা উচিত persist


3
এটি জেপিএ, সুতরাং আমি মনে করি সাদৃশ্যপূর্ণ পদ্ধতিটি। নিমজ্জন (), তবে এটি আমাকে একই ব্যতিক্রম দেয়। পরিষ্কার হতে হবে, লেনদেন একটি নতুন অবজেক্ট, অ্যাকাউন্ট নয়।
পল সানওয়াল্ড

@ পলসনওয়াল্ড অবজেক্টে ব্যবহার mergeকরে transactionআপনি কি একই ত্রুটি পেয়েছেন?
ড্যান

আসলে, না, আমি ভুল কথা বলেছি আমি যদি নিমজ্জন (লেনদেন) করি তবে লেনদেন মোটেই স্থির থাকে না।
পল সানওয়াল্ড

@ পলসানওয়াল্ড হুম, আপনি কি নিশ্চিত যে অটল transactionছিল না? কীভাবে চেক করলেন। নোট যা mergeস্থির অবজেক্টের একটি রেফারেন্স ফিরিয়ে দিচ্ছে।
ড্যান

.mers () দ্বারা ফিরে আসা বস্তুর একটি নাল আইডি রয়েছে। এছাড়াও, আমি পরে একটি .ফাইন্ডএল () করছি এবং আমার বস্তুটি সেখানে নেই।
পল সানওয়াল্ড

12

পদ্ধতি অব্যাহত রাখতে আইডি (পিকে) পাস করবেন না বা অবিচ্ছিন্ন () পরিবর্তে () পদ্ধতিটি সংরক্ষণ করার চেষ্টা করুন।


2
সদুপদেশ! তবে কেবল আইডি উত্পন্ন হলে। যদি এটি নির্ধারিত হয় তবে আইডি সেট করা স্বাভাবিক।
অ্যালডিয়ান

এটি আমার জন্য কাজ করেছে। এছাড়াও, আপনি TestEntityManager.persistAndFlush()কোনও পরিস্থিতি পরিচালনা ও স্থির করার জন্য ব্যবহার করতে পারেন তারপরে অন্তর্নিহীন ডেটাবেজে স্থিরতা প্রসঙ্গে সিঙ্ক্রোনাইজ করুন। আসল উত্স সত্তাটি
ফেরান

7

যেহেতু এটি একটি খুব সাধারণ প্রশ্ন, আমি এই নিবন্ধটি লিখেছি , যার ভিত্তিতে এই উত্তরটি ভিত্তিক।

সমস্যাটি সমাধান করার জন্য আপনাকে এই পদক্ষেপগুলি অনুসরণ করতে হবে:

1. শিশু সমিতি ক্যাসকেডিং অপসারণ

সুতরাং, আপনাকে সমিতি @CascadeType.ALLথেকে অপসারণ করতে হবে @ManyToOne। শিশু সত্তা পিতামাতার সমিতিগুলিতে ক্যাসকেড করা উচিত নয়। কেবলমাত্র পিতামাতার সত্তাগুলিই শিশু সত্তাকে ক্যাসকেড করা উচিত।

@ManyToOne(fetch= FetchType.LAZY)

খেয়াল করুন যে আমি fetchবৈশিষ্ট্যটি সেট করেছি FetchType.LAZYকারণ উত্সাহ আনতে পারফরম্যান্সের জন্য খুব খারাপ

2. সমিতির উভয় পক্ষ সেট করুন

যখনই আপনার দ্বি নির্দেশমূলক সমিতি রয়েছে, আপনার প্যারেন্ট সত্তায় উভয় দিক addChildএবং removeChildপদ্ধতিগুলি ব্যবহার করে সিঙ্ক্রোনাইজ করতে হবে :

public void addTransaction(Transaction transaction) {
    transcations.add(transaction);
    transaction.setAccount(this);
}

public void removeTransaction(Transaction transaction) {
    transcations.remove(transaction);
    transaction.setAccount(null);
}

দ্বিদলীয় অ্যাসোসিয়েশনের উভয় প্রান্তের সমলয় কেন গুরুত্বপূর্ণ তা সম্পর্কে আরও তথ্যের জন্য, এই নিবন্ধটি দেখুন


4

আপনার সত্তা সংজ্ঞা, আপনি উল্লেখ করছি না @JoinColumn জন্য Accountএকটি যোগদান Transaction। আপনি এরকম কিছু চাইবেন:

@Entity
public class Transaction {
    @ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
    @JoinColumn(name = "accountId", referencedColumnName = "id")
    private Account fromAccount;
}

সম্পাদনা: আচ্ছা, আমি অনুমান করি যে আপনি যদি @Tableআপনার ক্লাসে টিকাটি ব্যবহার করেন তবে তা কার্যকর হবে । হেহ। :)


2
হ্যাঁ, আমি মনে করি এটি ঠিক এটি নয়, আমি @ জোইনকলাম (নাম = "অ্যাকাউন্ট থেকে_ও", রেফারেন্সড কলামনাম = "আইডি") যুক্ত করেছি এবং এটি কার্যকর হয়নি :)।
পল সানওয়াল্ড

হ্যাঁ, আমি টেবিলগুলিতে সত্তাগুলির ম্যাপিংয়ের জন্য সাধারণত একটি ম্যাপিং এক্সএমএল ফাইল ব্যবহার করি না, তাই আমি সাধারণত ধরে নিই যে এটি এনোটেশন ভিত্তিক। তবে যদি আমার অনুমান করতেই হয়, আপনি সারণিগুলিতে মানচিত্রের জন্য একটি হাইবারনেট.এক্সএমএল ব্যবহার করছেন, তাই না?
NemesisX00

না, আমি স্প্রিং ডেটা জেপিএ ব্যবহার করছি, সুতরাং এটি সমস্ত টীকাভিত্তিক। আমার অন্যদিকে একটি "ম্যাপডবাই" টিকা আছে: @ ওনোটোম্যানি (ক্যাসকেড = {ক্যাসকেডটাইপ.এলএল}, ফেচ = ফেচটাইপ.এগ্রার, ম্যাপডবাই = "অ্যাকাউন্ট থেকে")
পল সানওয়াল্ড

4

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

@Entity
public class Transaction {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
....

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

বিকল্পভাবে, কিন্তু কার্যকরভাবে একই, এই টিকা ঘোষণার ফলাফল একই ব্যতিক্রম:

@Entity
public class Transaction {
    @Id
    @org.hibernate.annotations.GenericGenerator(name="system-uuid", strategy="uuid")
    @GeneratedValue(generator="system-uuid")
    private Long id;
....

সুতরাং, idআপনার অ্যাপ্লিকেশন কোডটিতে এটি ইতিমধ্যে পরিচালিত হওয়ার পরে মানটি সেট করবেন না ।


4

যদি কোনও কিছুই সহায়তা করে না এবং আপনি এখনও এই ব্যতিক্রম পাচ্ছেন তবে আপনার equals()পদ্ধতিগুলি পর্যালোচনা করুন - এবং এতে শিশু সংগ্রহ অন্তর্ভুক্ত করবেন না। বিশেষত যদি আপনার এম্বেড থাকা সংগ্রহের গভীর কাঠামো থাকে (যেমন এ-তে বিএস রয়েছে, বিতে রয়েছে সিএস ইত্যাদি)।

উদাহরণস্বরূপ Account -> Transactions:

  public class Account {

    private Long id;
    private String accountName;
    private Set<Transaction> transactions;

    @Override
    public boolean equals(Object obj) {
      if (this == obj)
        return true;
      if (obj == null)
        return false;
      if (!(obj instanceof Account))
        return false;
      Account other = (Account) obj;
      return Objects.equals(this.id, other.id)
          && Objects.equals(this.accountName, other.accountName)
          && Objects.equals(this.transactions, other.transactions); // <--- REMOVE THIS!
    }
  }

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


1

হতে পারে এটি ওপেনজেপিএর বাগ, রোলব্যাকটি যখন এটি @ ভার্সন ক্ষেত্রটি পুনরায় সেট করে তবে পিসি ভার্সনআইনাইট সত্য রাখে। আমার একটি অ্যাবস্ট্রাসএনটিটি রয়েছে যা @ সংস্করণ ক্ষেত্রটিকে ঘোষণা করেছে। আমি পিসি ভার্সনআইনিট ক্ষেত্রটি পুনরায় সেট করে এটির পুনরায় কাজ করতে পারি। তবে এটি একটি ভাল ধারণা নয়। আমি মনে করি যখন ক্যাসকেড সত্তা বজায় থাকে তখন এটি কার্যকর হয় না।

    private static Field PC_VERSION_INIT = null;
    static {
        try {
            PC_VERSION_INIT = AbstractEntity.class.getDeclaredField("pcVersionInit");
            PC_VERSION_INIT.setAccessible(true);
        } catch (NoSuchFieldException | SecurityException e) {
        }
    }

    public T call(final EntityManager em) {
                if (PC_VERSION_INIT != null && isDetached(entity)) {
                    try {
                        PC_VERSION_INIT.set(entity, false);
                    } catch (IllegalArgumentException | IllegalAccessException e) {
                    }
                }
                em.persist(entity);
                return entity;
            }

            /**
             * @param entity
             * @param detached
             * @return
             */
            private boolean isDetached(final Object entity) {
                if (entity instanceof PersistenceCapable) {
                    PersistenceCapable pc = (PersistenceCapable) entity;
                    if (pc.pcIsDetached() == Boolean.TRUE) {
                        return true;
                    }
                }
                return false;
            }

1

আপনাকে প্রতিটি অ্যাকাউন্টের জন্য লেনদেন সেট করতে হবে।

foreach(Account account : accounts){
    account.setTransaction(transactionObj);
}

অথবা অনেক দিক থেকে আইডিকে সেট করার পক্ষে এটি উপযুক্ত (উপযুক্ত হলে) যথেষ্ট।

// list of existing accounts
List<Account> accounts = new ArrayList<>(transactionObj.getAccounts());

foreach(Account account : accounts){
    account.setId(null);
}

transactionObj.setAccounts(accounts);

// just persist transactionObj using EntityManager merge() method.

1
cascadeType.MERGE,fetch= FetchType.LAZY

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

ভিএলকিউ পর্যালোচক: মেটা.স্ট্যাকওভারফ্লো . com/ প্রশ্নগুলি / ২2০০১১/২ দেখুন । কোড-কেবলমাত্র উত্তরগুলি মুছে ফেলার যোগ্য নয়, উপযুক্ত ক্রিয়াটি "ঠিক আছে মনে হচ্ছে" নির্বাচন করা।
নাথান হিউজেস

1

আমার স্প্রিং ডেটা জেপিএ ভিত্তিক উত্তর: আমি কেবল @Transactionalআমার বাইরের পদ্ধতিতে একটি টীকা যোগ করেছি।

কেন এটি কাজ করে

শিশু সত্তা অবিলম্বে বিচ্ছিন্ন হয়ে উঠছিল কারণ কোনও হাইবারনেট সেশন প্রসঙ্গ ছিল না। একটি স্প্রিং (ডেটা জেপিএ) লেনদেন সরবরাহ একটি হাইবারনেট সেশন উপস্থিত থাকার নিশ্চয়তা দেয়।

রেফারেন্স:

https://vladmihalcea.com/a-beginners-guide-to-jpa-hibernate-entity-state-transitions/


0

আমার ক্ষেত্রে আমি যখন অবিচ্ছিন্ন পদ্ধতি ব্যবহার করা হত তখন আমি লেনদেন করছিলাম । পদ্ধতিটি সংরক্ষণে অবিচলিত পরিবর্তন করার পরে , এটি সমাধান হয়ে গেছে।


0

যদি উপরের সমাধানগুলি কাজ না করে তবে একবারে সত্তা শ্রেণীর প্রাপ্তকারী এবং সেটার পদ্ধতিগুলির মন্তব্য করুন এবং আইডির মান সেট না করে। (প্রাথমিক কী) তাহলে এটি কাজ করবে।


0

@ ওনোটোমনি (ম্যাপডবাই = "এক্সএক্সএক্সএক্সএক্স", ক্যাসকেড = {ক্যাসকেডটাইপ.মারজি, ক্যাসকেডটাইপ.প্রেসিস্ট, ক্যাসকেডটাইপ.আরমোভ}) আমার পক্ষে কাজ করেছে।


0

পরেরটির আগে নির্ভরশীল বস্তুকে সংরক্ষণ করে সমাধান করা হয়েছে।

আমার সাথে এটি ঘটেছিল কারণ আমি আইডি সেট করছিলাম না (যা স্বয়ংক্রিয়ভাবে উত্পন্ন হয়নি)। এবং সম্পর্কের সাথে যোগাযোগ করুন @ মান্টোওনে

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.