জেপিএ হ্যাশকোড () / সমান () দ্বিধা


311

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

সমস্ত সম্ভাব্য বাস্তবায়নের সাথে সম্পর্কিত নিজস্ব সুবিধা এবং অসুবিধাগুলি রয়েছে :

  • hashCode()/equals() চুক্তি সাদৃশ্য (অপরিবর্তনীয়তা) জন্য List/ Setঅপারেশন
  • কিনা অভিন্ন বস্তু (যেমন বিভিন্ন সেশন থেকে, প্রখর রৌদ্রে লোড ডাটা স্ট্রাকচার থেকে গতিশীল প্রক্সি) সনাক্ত করা যাবে
  • সত্তা বিচ্ছিন্ন (বা অ-স্থিত) অবস্থায় সঠিকভাবে আচরণ করে কিনা

আমি যতদূর দেখতে পাচ্ছি, এখানে তিনটি বিকল্প রয়েছে :

  1. এগুলি ওভাররাইড করবেন না; উপর নির্ভর করে Object.equals()এবংObject.hashCode()
    • hashCode()/ equals()কাজ
    • অভিন্ন বস্তু, গতিশীল প্রক্সি সহ সমস্যা সনাক্ত করতে পারে না
    • বিচ্ছিন্ন সত্তা নিয়ে কোনও সমস্যা নেই
  2. প্রাথমিক কী এর উপর ভিত্তি করে সেগুলি ওভাররাইড করুন
    • hashCode()/ equals()ভেঙে গেছে
    • সঠিক পরিচয় (সমস্ত পরিচালিত সত্তার জন্য)
    • বিচ্ছিন্ন সত্তা নিয়ে সমস্যা
  3. বিজনেস-আইডির ভিত্তিতে এগুলি ওভাররাইড করুন (অ-প্রাথমিক কী ক্ষেত্রসমূহ; বিদেশী কী সম্পর্কে কী?)
    • hashCode()/ equals()ভেঙে গেছে
    • সঠিক পরিচয় (সমস্ত পরিচালিত সত্তার জন্য)
    • বিচ্ছিন্ন সত্তা নিয়ে কোনও সমস্যা নেই

আমার প্রশ্নগুলি হ'ল:

  1. আমি কি কোনও বিকল্প এবং / অথবা প্রো / কন পয়েন্ট মিস করেছি?
  2. আপনি কোন বিকল্পটি বেছে নিয়েছিলেন এবং কেন?



আপডেট 1:

দ্বারা " hashCode()/ equals()ভাঙা হয়", আমি যে ধারাবাহিক মানে hashCode()আমন্ত্রণ বিভিন্নমুখী মান ফেরত দিতে পারেন, যা (যখন সঠিকভাবে বাস্তবায়িত) অর্থে ভাঙ্গা না Objectএপিআই ডকুমেন্টেশন, কিন্তু যখন একটি থেকে একটি পরিবর্তিত সত্তা পুনরুদ্ধার করতে চেষ্টা যা সমস্যার কারণ Map, Setবা অন্যান্য হ্যাশ-ভিত্তিক Collection। ফলস্বরূপ, জেপিএ বাস্তবায়ন (কমপক্ষে এক্লিপস লিঙ্ক) কিছু ক্ষেত্রে সঠিকভাবে কাজ করবে না।

আপডেট 2:

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


4
"হ্যাশকোড () / সমান () ভাঙা"
নন্দা

4
সেগুলি তখন সেই অর্থে "ভাঙ্গা" হবে না, বিকল্প 2 এবং 3 হিসাবে আপনি একই কৌশল ব্যবহার করে সমান () এবং হ্যাশকোড () উভয়ই প্রয়োগ করবেন।
ম্যাট বি

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

1
প্রকৃতপক্ষে বাক্যটির সেই অংশটির বিপরীত অর্থ হয় - hashcode()একই বস্তুর উদাহরণের জন্য আহ্বানের একই মানটি ফিরিয়ে নেওয়া উচিত, যতক্ষণ না equals()বাস্তবায়নের পরিবর্তনের ক্ষেত্রে কোনও ক্ষেত্র ব্যবহৃত হয় । অন্য কথায়, যদি আপনার ক্লাসে তিনটি ক্ষেত্র থাকে এবং আপনার equals()পদ্ধতি উদাহরণগুলির সাম্যতা নির্ধারণের জন্য কেবল তার দুটি মাত্র ব্যবহার করে, তবে আপনি hashcode()যদি ক্ষেত্রের মানগুলির মধ্যে একটি পরিবর্তন করেন তবে আপনি প্রত্যাবর্তনের মান পরিবর্তন করতে পারবেন - যা বিবেচনা করার সময় আপনি তা বিবেচনা করতে পারবেন এই বস্তুর উদাহরণটি পুরানো উদাহরণটি উপস্থাপন করে এমন মানটির সাথে আর "সমান" নয়।
ম্যাট বি বি

2
"মানচিত্র, সেট বা অন্যান্য হ্যাশ-ভিত্তিক সংগ্রহ থেকে পরিবর্তিত সত্তা পুনরুদ্ধারের চেষ্টা করার সময় সমস্যাগুলি" ... এটি হ্যাশম্যাপ, হ্যাশসেট বা অন্যান্য হ্যাশ-ভিত্তিক সংগ্রহগুলি থেকে পরিবর্তিত সত্তা পুনরুদ্ধারের চেষ্টা করার সময় সমস্যা হওয়া উচিত "
নন্দ

উত্তর:


122

বিষয়টিতে এই খুব সুন্দর নিবন্ধটি পড়ুন: হাইবারনেটকে আপনার পরিচয় চুরি করতে দেবেন না

নিবন্ধের উপসংহারটি এরকম হয়:

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


21
না, এটি একটি নিবন্ধ নয়। এটি বিষয়টির উপর একটি ফ্রিকিং দুর্দান্ত নিবন্ধ এবং এটি প্রতিটি জেপিএ প্রোগ্রামারের জন্য পড়া দরকার! +1 টি!
টম অ্যান্ডারসন

2
হ্যাঁ আমি একই সমাধানটি ব্যবহার করছি। ডিবি আইডি তৈরি করতে না দেওয়ার অন্যান্য সুবিধাও রয়েছে, যেমন কোনও বস্তু তৈরি করতে সক্ষম হওয়া এবং ইতিমধ্যে অন্যান্য অবজেক্ট তৈরি করা যা এটি চালিয়ে যাওয়ার আগে এটি রেফারেন্স করে। এটি ক্লায়েন্ট-সার্ভার অ্যাপ্লিকেশনগুলিতে বিলম্বিতা এবং একাধিক অনুরোধ / প্রতিক্রিয়াচক্র সরাতে পারে। আপনার যদি এই জাতীয় সমাধানের জন্য অনুপ্রেরণার প্রয়োজন হয় তবে আমার প্রকল্পগুলি দেখুন: suid.js এবং suid -server-java । মূলত suid.jsআইডি ব্লকগুলি এনে দেয় suid-server-javaযা থেকে আপনি ক্লায়েন্ট- সাইডটি পেতে এবং ব্যবহার করতে পারেন।
স্টিজন ডি উইট

2
এটি কেবল উন্মাদ। আমি হুডের অধীনে কাজ হাইবারনেট করতে নতুন, ইউনিট পরীক্ষা লিখছিলাম, এবং জানতে পেরেছিলাম যে আমি কোনও সেটকে সংশোধন করার পরে মুছতে পারি না, সিদ্ধান্ত নিয়েছে যে এটি হ্যাশকোড পরিবর্তনের কারণে হয়েছে, তবে কীভাবে বুঝতে অক্ষম ছিল সমাধান করা. নিবন্ধটি খুব সরল!
এক্সএমাইট

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

1
হাইবারনেট / জেপিএ ডাটাবেসে রেকর্ডটি ইতিমধ্যে বিদ্যমান কিনা তা পরীক্ষা করতে কোনও সত্তার সমান এবং হ্যাশকোড পদ্ধতি ব্যবহার করে?
তুষার বান্ন

64

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

এই সমস্ত স্টাফটি যোগ করার জন্য, এখানে সমান / হ্যাশকোডগুলি হ্যান্ডল করার বিভিন্ন উপায়ে কী কাজ করবে বা কী কাজ করবে না তার একটি তালিকা এখানে রয়েছে: এখানে চিত্র বর্ণনা লিখুন

সম্পাদনা :

এটি আমার জন্য কেন কাজ করে তা ব্যাখ্যা করতে:

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

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

প্রশ্নের মন্তব্য দেখুন। আপনি সমান / হ্যাশকোড চুক্তি ভুল বুঝা বলে মনে হয়
নন্দ

1
@ এমআরালওয়াসার: আমার মনে হয় আপনি সঠিক জিনিসটি বোঝাচ্ছেন, এটি কেবল সমান / হ্যাশকোড () চুক্তি নয় যা লঙ্ঘিত। তবে একটি পরিবর্তনীয় সমান / হ্যাশকোড সেট চুক্তিতে সমস্যা তৈরি করে ।
ক্রিস লেকারের

3
@ এমআরালওয়াসার: হ্যাশকোড কেবল তখনই বদলে যাবে যখন ব্যবসায়ের আইডি পরিবর্তন হয় এবং মূল বিষয় হ'ল ব্যবসায়ের আইডি পরিবর্তন হয় না । সুতরাং হ্যাশকোড পরিবর্তন হয় না এবং এটি হ্যাশ সংগ্রহের সাথে পুরোপুরি কাজ করে।
টম অ্যান্ডারসন

1
আপনার যদি প্রাকৃতিক ব্যবসায়ের চাবি না থাকে তবে কী হবে? উদাহরণস্বরূপ, গ্রাফ-অঙ্কন অ্যাপ্লিকেশনটিতে একটি দ্বিমাত্রিক বিন্দুর ক্ষেত্রে পয়েন্ট (এক্স, ওয়াই)? কীভাবে আপনি এই পয়েন্টটি সত্তা হিসাবে সংরক্ষণ করবেন?
heেগেগাস

35

আমাদের সত্তায় সাধারণত দুটি আইডি থাকে:

  1. কেবলমাত্র অধ্যবসায়ের স্তরের জন্য (যাতে অধ্যবসায় সরবরাহকারী এবং ডাটাবেসগুলি বস্তুর মধ্যে সম্পর্ক নির্ধারণ করতে পারে)।
  2. আমাদের অ্যাপ্লিকেশন প্রয়োজনের জন্য ( equals()এবং hashCode()বিশেষত)

এটা দেখ:

@Entity
public class User {

    @Id
    private int id;  // Persistence ID
    private UUID uuid; // Business ID

    // assuming all fields are subject to change
    // If we forbid users change their email or screenName we can use these
    // fields for business ID instead, but generally that's not the case
    private String screenName;
    private String email;

    // I don't put UUID generation in constructor for performance reasons. 
    // I call setUuid() when I create a new entity
    public User() {
    }

    // This method is only called when a brand new entity is added to 
    // persistence context - I add it as a safety net only but it might work 
    // for you. In some cases (say, when I add this entity to some set before 
    // calling em.persist()) setting a UUID might be too late. If I get a log 
    // output it means that I forgot to call setUuid() somewhere.
    @PrePersist
    public void ensureUuid() {
        if (getUuid() == null) {
            log.warn(format("User's UUID wasn't set on time. " 
                + "uuid: %s, name: %s, email: %s",
                getUuid(), getScreenName(), getEmail()));
            setUuid(UUID.randomUUID());
        }
    }

    // equals() and hashCode() rely on non-changing data only. Thus we 
    // guarantee that no matter how field values are changed we won't 
    // lose our entity in hash-based Sets.
    @Override
    public int hashCode() {
        return getUuid().hashCode();
    }

    // Note that I don't use direct field access inside my entity classes and
    // call getters instead. That's because Persistence provider (PP) might
    // want to load entity data lazily. And I don't use 
    //    this.getClass() == other.getClass() 
    // for the same reason. In order to support laziness PP might need to wrap
    // my entity object in some kind of proxy, i.e. subclassing it.
    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (!(obj instanceof User))
            return false;
        return getUuid().equals(((User) obj).getUuid());
    }

    // Getters and setters follow
}

সম্পাদনা:setUuid() পদ্ধতিতে কল সম্পর্কিত আমার বক্তব্য পরিষ্কার করতে । এখানে একটি সাধারণ দৃশ্য রয়েছে:

User user = new User();
// user.setUuid(UUID.randomUUID()); // I should have called it here
user.setName("Master Yoda");
user.setEmail("yoda@jedicouncil.org");

jediSet.add(user); // here's bug - we forgot to set UUID and 
                   //we won't find Yoda in Jedi set

em.persist(user); // ensureUuid() was called and printed the log for me.

jediCouncilSet.add(user); // Ok, we got a UUID now

আমি যখন আমার পরীক্ষাগুলি চালনা করি এবং লগ আউটপুট দেখি আমি সমস্যার সমাধান করি:

User user = new User();
user.setUuid(UUID.randomUUID());

বিকল্পভাবে, একটি পৃথক নির্মাণকারী সরবরাহ করতে পারে:

@Entity
public class User {

    @Id
    private int id;  // Persistence ID
    private UUID uuid; // Business ID

    ... // fields

    // Constructor for Persistence provider to use
    public User() {
    }

    // Constructor I use when creating new entities
    public User(UUID uuid) {
        setUuid(uuid);
    }

    ... // rest of the entity.
}

সুতরাং আমার উদাহরণটি এর মতো দেখাবে:

User user = new User(UUID.randomUUID());
...
jediSet.add(user); // no bug this time

em.persist(user); // and no log output

আমি একটি ডিফল্ট কনস্ট্রাক্টর এবং একটি সেটার ব্যবহার করি তবে আপনি দ্বি-কনস্ট্রাক্টর আপনার কাছে আরও উপযোগী হতে পারেন।


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

4
এটি কীভাবে জেভিএম সমতা এবং অধ্যবসায়ের সাম্যের জন্য ডিফল্ট hashCode/ equalsপদ্ধতিগুলি ব্যবহার করে আলাদা id? এটি আমার কাছে মোটেই বোঝা যায় না।
বেহরং সাইদজাদেহে

2
এটি ক্ষেত্রে কার্যকর হয় যখন আপনার কাছে বেশ কয়েকটি সত্তা অবজেক্ট থাকে যখন একটি ডাটাবেসে একই সারিটিতে নির্দেশ করে। Objectএর equals()ফিরে আসবে falseএই ক্ষেত্রে। UUID ভিত্তিক equals()আয় true
অ্যান্ড্রু Листочкин Листочкин

4
-1 - আমি দুটি আইডি থাকার কোনও কারণ দেখতে পাচ্ছি না, এবং তাই দুই প্রকারের পরিচয়। এটি আমার কাছে সম্পূর্ণ অর্থহীন এবং সম্ভাব্য ক্ষতিকারক বলে মনে হচ্ছে।
টম অ্যান্ডারসন

1
আমি পছন্দ করি এমন কোনও দিকে ইঙ্গিত না করে আপনার সমাধানটির সমালোচনা করার জন্য দুঃখিত। সংক্ষেপে, আমি বস্তুকে একটি একক আইডি ক্ষেত্র দেব, আমি এর উপর ভিত্তি করে সমান এবং হ্যাশকোড প্রয়োগ করব এবং আমি ডাটাবেসে সংরক্ষণ করার পরিবর্তে অবজেক্ট তৈরির উপর এর মান উত্পন্ন করব। এইভাবে, সমস্ত ধরণের অবজেক্ট একইভাবে কাজ করে: অবিচল, অবিচলিত এবং বিচ্ছিন্ন det হাইবারনেট প্রক্সিগুলি (বা অনুরূপ) এছাড়াও সঠিকভাবে কাজ করা উচিত এবং আমি মনে করি সমান এবং হ্যাশকোড কলগুলি হ্যান্ডেল করার জন্য এমনকি হাইড্রেট করা প্রয়োজন হবে না।
টম অ্যান্ডারসন

31

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

তবে আরও বিকল্প রয়েছে (তাদের উপকারিতা এবং বিপরীতেও):


ক) হ্যাশকোড / একটি সেট উপর ভিত্তি করে সমান অপরিবর্তনীয় , নাল না , নির্ধারিত কন্সট্রাকটর ক্ষেত্রগুলি

(+) তিনটি মানদণ্ডই গ্যারান্টিযুক্ত

(-) ক্ষেত্রের মানগুলি একটি নতুন উদাহরণ তৈরি করতে অবশ্যই উপলব্ধ

(-) হ্যান্ডলিংকে জটিল করে তোলে যদি আপনার অবশ্যই একটির পরিবর্তন করতে হবে


খ) জেপিএর পরিবর্তে অ্যাপ্লিকেশন দ্বারা নির্ধারিত একটি প্রাথমিক কী-এর ভিত্তিতে হ্যাশকোড / সমান

(+) তিনটি মানদণ্ডই গ্যারান্টিযুক্ত

(-) আপনি ডিবি সিকোয়েন্সগুলির মতো সাধারণ নির্ভরযোগ্য আইডি প্রজন্মের অবস্থার সুবিধা নিতে পারবেন না

(-) বিতরণ পরিবেশে (ক্লায়েন্ট / সার্ভার) বা অ্যাপ সার্ভার ক্লাস্টারে নতুন সত্তা তৈরি করা হলে জটিল complicated


গ) হ্যাশকোড / একটি উপর ভিত্তি করে সমান UUID সত্তা কন্সট্রাকটর দ্বারা নিয়োগ

(+) তিনটি মানদণ্ডই গ্যারান্টিযুক্ত

(-) ইউআইডি প্রজন্মের ওভারহেড

(-) ব্যবহার করা অ্যালগরিদমের উপর নির্ভর করে একই ইউএইউডের দ্বিগুণ ব্যবহৃত হওয়ার সামান্য ঝুঁকি হতে পারে (ডিবিতে একটি অনন্য সূচক দ্বারা সনাক্ত করা যেতে পারে)


আমি অপশন 1 এবং অ্যাপ্রোচ সি এর ভক্ত । আপনার একেবারে প্রয়োজন না হওয়া পর্যন্ত কিছুই করবেন না এটি আরও চতুর পদ্ধতির।
অ্যাডাম জেন্ট

2
বিকল্পের জন্য +1 (খ)। আইএমএইচও, যদি কোনও সত্তার একটি প্রাকৃতিক ব্যবসায় আইডি থাকে, তবে এটির ডাটাবেস প্রাথমিক কীও হওয়া উচিত। এটি সহজ, সোজা, ভাল ডাটাবেস ডিজাইন। যদি এর মতো আইডি না থাকে তবে একটি সারোগেট কী প্রয়োজন। যদি আপনি এটি অবজেক্ট তৈরিতে সেট করে থাকেন তবে সমস্ত কিছু সহজ। লোকেরা যখন কোনও প্রাকৃতিক কী ব্যবহার করেন না এবং কোনও সমস্যায় পড়েন তাড়াতাড়ি কোনও সারোগেট কী তৈরি করবেন না It's বাস্তবায়নে জটিলতা হিসাবে - হ্যাঁ, কিছু আছে। তবে সত্যিই খুব বেশি কিছু নয় এবং এটি খুব জেনেরিক উপায়ে করা যেতে পারে যা এটি সমস্ত সত্তার জন্য একবার সমাধান করে।
টম অ্যান্ডারসন

আমি বিকল্প 1ও পছন্দ করি তবে তারপরে কীভাবে ইউনিট পরীক্ষা লিখতে হবে সম্পূর্ণ সাম্য্যতা একটি বড় সমস্যা, কারণ আমাদের জন্য সমান পদ্ধতিটি প্রয়োগ করতে হবে Collection
ওওডি ওয়াটারবল

শুধু এটা করবেন না। দেখুন কি হাইবারনেট সাথে বিশৃঙ্খলা করবেন
alonana

29

যদি আপনি equals()/hashCode()আপনার সেটের জন্য ব্যবহার করতে চান , সেই অর্থে যে একই সত্তা কেবল একবারে সেখানে থাকতে পারে, তবে কেবলমাত্র একটি বিকল্প রয়েছে: বিকল্প 2. কারণ এটি একটি প্রাথমিক কী সংজ্ঞা অনুসারে কোনও সত্তার জন্য কখনও পরিবর্তন হয় না (যদি কেউ সত্যই আপডেট করে তবে এটি, এটি আর একই সত্তা নয়)

আপনার এটি আক্ষরিকভাবে নেওয়া উচিত: যেহেতু আপনার equals()/hashCode()প্রাথমিক কী উপর ভিত্তি করে, প্রাথমিক কী সেট না হওয়া অবধি আপনার এই পদ্ধতিগুলি ব্যবহার করা উচিত নয়। সুতরাং সেগুলিতে সত্ত্বা স্থাপন করা উচিত নয়, যতক্ষণ না তাদের একটি প্রাথমিক কী অর্পণ করা হয়। (হ্যাঁ, ইউআইডি এবং অনুরূপ ধারণাগুলি প্রাথমিক কীগুলি প্রথম দিকে নির্ধারিত করতে সহায়তা করতে পারে))

এখন, তাত্ত্বিকভাবে এটি অপশন 3 দ্বারা অর্জন করা সম্ভব, তথাকথিত "বিজনেস-কীগুলি" এর যে খারাপ অভ্যাস রয়েছে তা তারা পরিবর্তন করতে পারে: "আপনাকে যা করতে হবে তা হ'ল সেট থেকে ইতিমধ্যে প্রবেশ করা সত্তা মুছে ফেলা ( গুলি), এবং সেগুলি পুনরায় .োকান। " এটি সত্য - তবে এর অর্থ হ'ল, বিতরণ করা সিস্টেমে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে, ডেটা theোকানো হয়েছে ঠিক সেখানেই এটি সম্পন্ন হয়েছে (এবং আপনাকে নিশ্চিত করতে হবে, আপডেটটি সম্পাদিত হয়েছে , অন্যান্য জিনিস হওয়ার আগে)। আপনার একটি পরিশীলিত আপডেট পদ্ধতি দরকার হবে, বিশেষত যদি কিছু রিমোট সিস্টেম বর্তমানে পৌঁছতে না পারে ...

আপনার সেটগুলির সমস্ত বস্তু যদি একই হাইবারনেট সেশন থেকে থাকে তবে বিকল্প 1 টি কেবলমাত্র ব্যবহৃত হতে পারে। হাইবারনেট ডকুমেন্টেশন এটিকে 13.1.3 অনুচ্ছেদে খুব স্পষ্ট করে তুলেছে। অবজেক্টের পরিচয় বিবেচনা :

একটি সেশনের মধ্যে অ্যাপ্লিকেশনটি নিরাপদে == অবজেক্টগুলির তুলনা করতে ব্যবহার করতে পারে।

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

এটি বিকল্প 3 এর পক্ষে যুক্তি অব্যাহত রেখেছে:

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

এটি সত্য, যদি আপনি

  • আইডি তাড়াতাড়ি বরাদ্দ করতে পারে না (যেমন ইউআইডি ব্যবহার করে)
  • এবং তবুও আপনি সম্পূর্ণরূপে আপনার বস্তুগুলি ক্ষণস্থায়ী অবস্থায় সেটগুলিতে রাখতে চান।

অন্যথায়, আপনি বিকল্প 2 চয়ন করতে নিখরচায় রয়েছেন।

তারপরে এটি একটি আপেক্ষিক স্থিতিশীলতার প্রয়োজন উল্লেখ করেছে:

ব্যবসায়িক কীগুলির বৈশিষ্ট্যগুলি ডাটাবেস প্রাথমিক কীগুলির মতো স্থিতিশীল হতে হবে না; আপনাকে কেবলমাত্র স্থায়ীত্বের গ্যারান্টি দিতে হবে যতক্ষণ না অবজেক্টগুলি একই সেটে থাকে।

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


সংক্ষিপ্ত সংস্করণ:

  • বিকল্প 1 কেবলমাত্র একক সেশনের মধ্যে অবজেক্টগুলির সাথে ব্যবহার করা যেতে পারে।
  • আপনি যদি পারেন তবে অপশন 2 ব্যবহার করুন (যত তাড়াতাড়ি সম্ভব পিকে বরাদ্দ দিন, কারণ পিকে বরাদ্দ না দেওয়া পর্যন্ত আপনি সেটগুলিতে অবজেক্টগুলি ব্যবহার করতে পারবেন না।)
  • আপনি যদি আপেক্ষিক স্থিতিশীলতার গ্যারান্টি দিতে পারেন তবে আপনি অপশন ৩ ব্যবহার করতে পারেন But তবে এটির সাথে সতর্ক থাকুন।

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

2
@ উইলিয়াম: কোনও সত্তার প্রাথমিক কী পরিবর্তন হয় না। ম্যাপযুক্ত বস্তুর আইডি সম্পত্তি পরিবর্তন হতে পারে। এটি ঘটেছিল, যেমনটি আপনি ব্যাখ্যা করেছেন, বিশেষত যখন একটি ক্ষণস্থায়ী বস্তু স্থির করা হয় । দয়া করে আমার উত্তরের অংশটি মনোযোগ সহকারে পড়ুন, যেখানে আমি সমান / হ্যাশকোড পদ্ধতিগুলি সম্পর্কে বলেছিলাম: "প্রাথমিক কী সেট না হওয়া পর্যন্ত আপনার অবশ্যই এই পদ্ধতিগুলি ব্যবহার করা উচিত নয়" "
ক্রিস Lercher

সম্পূর্ণ একমত. বিকল্প 2 এর সাহায্যে আপনি একটি সুপার ক্লাসে সমান / হ্যাশকোড তৈরি করতে সক্ষম হন এবং এটি আপনার সমস্ত সত্তা পুনরায় ব্যবহার করতে পারেন।
থিও

+1 আমি জেপিএ-তে নতুন, তবে এখানে কিছু মন্তব্য এবং উত্তরগুলি বোঝায় যে লোকেরা "প্রাথমিক কী" শব্দের অর্থ বুঝতে পারে না।
রায়েডওয়াল্ড

16
  1. আপনার যদি একটি ব্যবসায়িক কী থাকে তবে আপনার equals/ এর জন্য এটি ব্যবহার করা উচিত hashCode
  2. আপনার যদি ব্যবসায়ের কী না থাকে তবে আপনার এটিকে ডিফল্ট Objectসমান এবং হ্যাশকোড প্রয়োগের সাথে ছেড়ে দেওয়া উচিত নয় কারণ এটি আপনার mergeএবং সত্তার পরে কাজ করে না ।
  3. আপনি এই পোস্টে প্রস্তাবিত হিসাবে সত্তা সনাক্তকারী ব্যবহার করতে পারেন । কেবল ধরাটি হ'ল আপনাকে এমন একটি hashCodeবাস্তবায়ন ব্যবহার করতে হবে যা সর্বদা একই মান প্রদান করে:

    @Entity
    public class Book implements Identifiable<Long> {
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String title;
    
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Book)) return false;
            Book book = (Book) o;
            return getId() != null && Objects.equals(getId(), book.getId());
        }
    
        @Override
        public int hashCode() {
            return 31;
        }
    
        //Getters and setters omitted for brevity
    }

(1): কোনটা ভাল onjava.com/pub/a/onjava/2006/09/13/... বা (2) vladmihalcea.com/... ? সমাধান (2) এর চেয়ে সহজ (1)। তাহলে আমার কেন ব্যবহার করা উচিত (1)। উভয়ের প্রভাব কি একই? উভয়ই কি একই সমাধানের গ্যারান্টি দেয়?
nimo23

এবং আপনার সমাধান সহ: একই উদাহরণগুলির মধ্যে "হ্যাশকোড মান পরিবর্তন হয় না"। এটির সাথে একই আচরণ রয়েছে যেন এটি "একই" ইউউইড (সমাধান (1) থেকে) তুলনা করা হচ্ছে। আমি কি সঠিক?
nimo23

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

1
আপনার যদি একটি অপরিবর্তনীয় ব্যবসায়ের কী থাকে, হ্যাশকোড এটি ব্যবহার করতে পারে এবং এটি একাধিক বালতি থেকে উপকৃত হতে পারে, তাই আপনার যদি এটি থাকে তবে এটি ব্যবহার করার পক্ষে উপযুক্ত। অন্যথায়, শুধু আমার নিবন্ধে বর্ণিত হিসাবে সত্তা সনাক্তকারী ব্যবহার করুন।
ভ্লাদ মিহলসিয়া

1
আমি আনন্দিত আপনি এটা পছন্দ করেছে. জেপিএ এবং হাইবারনেট সম্পর্কে আমার আরও আরও নিবন্ধ রয়েছে।
ভ্লাদ মিহলসিয়া

10

যদিও ব্যবসায়ের কী (বিকল্প 3) ব্যবহার করা সর্বাধিক প্রস্তাবিত পদ্ধতির ( হাইবারনেট সম্প্রদায়ের উইকি , "হাইবারনেট সহ জাভা পার্সিস্টেনস" পৃষ্ঠা 398), এবং এটি আমরা বেশিরভাগই ব্যবহার করি, সেখানে একটি হাইবারনেট বাগ রয়েছে যা আগ্রহী-আপদের জন্য এটি ভেঙে দেয় সেটগুলি: HHH-3799 । এই ক্ষেত্রে, হাইবারনেট ক্ষেত্রগুলি শুরু করার আগে কোনও সেটে একটি সত্তা যুক্ত করতে পারে। আমি নিশ্চিত নই কেন এই ত্রুটিটি আরও বেশি মনোযোগ পাচ্ছে না, কারণ এটি প্রস্তাবিত ব্যবসায়-কী পদ্ধতিরটিকে সত্যই সমস্যাযুক্ত করে তুলেছে।

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

যে পাতার একমাত্র বিকল্প 1, বস্তু পরিচয়ের ভিত্তিতে inheriting java.lang.Object বাস্তবায়নের, অথবা একটি অ্যাপ্লিকেশন-পরিচালিত প্রাথমিক কী ব্যবহার হিসাবে জেমস Brundege দ্বারা প্রস্তাবিত "do হাইবারনেট আপনার পরিচয় চুরি করা যাক নয়" (ইতিমধ্যে Stijn Geukens এর উত্তর দ্বারা রেফারেন্সড ) এবং "অবজেক্ট জেনারেশন: হাইবারনেট ইন্টিগ্রেশন টু বেটার অ্যাপ্রোচ" তে ল্যান্স আরলাউস লিখেছেন ।

বিকল্প 1 এর সাথে সবচেয়ে বড় সমস্যা হ'ল বিচ্ছিন্ন দৃষ্টান্তগুলি .equals () ব্যবহার করে অবিচ্ছিন্ন দৃষ্টান্তগুলির সাথে তুলনা করা যায় না। তবে তা ঠিক আছে; সমতুল্য এবং হ্যাশকোডের চুক্তিটি প্রতিটি শ্রেণীর জন্য সাম্য কী বোঝায় তা নির্ধারণ করতে এটি বিকাশকারীকে ছেড়ে দেয়। সুতরাং কেবল সমান এবং হ্যাশকোড অবজেক্ট থেকে উত্তরাধিকার সূত্রে আসুন। যদি আপনাকে কোনও অবিচ্ছিন্ন উদাহরণের সাথে একটি অবিচ্ছিন্ন উদাহরণের সাথে তুলনা করতে হয়, আপনি সেই উদ্দেশ্যে স্পষ্টভাবে একটি নতুন পদ্ধতি তৈরি করতে পারেন, সম্ভবত boolean sameEntityবা boolean dbEquivalentবা boolean businessEquals


5

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

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

@MappedSuperclass
public abstract class AbstractJpaEntity extends AbstractMutable implements Identifiable, Modifiable {

    private static final long   serialVersionUID    = 1L;

    @Version
    @Column(name = "version", nullable = false)
    private int                 version             = 0;

    @Column(name = "uuid_least_sig_bits")
    private long                uuidLeastSigBits    = 0;

    @Column(name = "uuid_most_sig_bits")
    private long                uuidMostSigBits     = 0;

    private transient int       hashCode            = 0;

    public AbstractJpaEntity() {
        //
    }

    public abstract Integer getId();

    public abstract void setId(final Integer id);

    public boolean isPersisted() {
        return getId() != null;
    }

    public int getVersion() {
        return version;
    }

    //calling UUID.randomUUID() is pretty expensive, 
    //so this is to lazily initialize uuid bits.
    private void initUUID() {
        final UUID uuid = UUID.randomUUID();
        uuidLeastSigBits = uuid.getLeastSignificantBits();
        uuidMostSigBits = uuid.getMostSignificantBits();
    }

    public long getUuidLeastSigBits() {
        //its safe to assume uuidMostSigBits of a valid UUID is never zero
        if (uuidMostSigBits == 0) {
            initUUID();
        }
        return uuidLeastSigBits;
    }

    public long getUuidMostSigBits() {
        //its safe to assume uuidMostSigBits of a valid UUID is never zero
        if (uuidMostSigBits == 0) {
            initUUID();
        }
        return uuidMostSigBits;
    }

    public UUID getUuid() {
        return new UUID(getUuidMostSigBits(), getUuidLeastSigBits());
    }

    @Override
    public int hashCode() {
        if (hashCode == 0) {
            hashCode = (int) (getUuidMostSigBits() >> 32 ^ getUuidMostSigBits() ^ getUuidLeastSigBits() >> 32 ^ getUuidLeastSigBits());
        }
        return hashCode;
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof AbstractJpaEntity)) {
            return false;
        }
        //UUID guarantees a pretty good uniqueness factor across distributed systems, so we can safely
        //dismiss getClass().equals(obj.getClass()) here since the chance of two different objects (even 
        //if they have different types) having the same UUID is astronomical
        final AbstractJpaEntity entity = (AbstractJpaEntity) obj;
        return getUuidMostSigBits() == entity.getUuidMostSigBits() && getUuidLeastSigBits() == entity.getUuidLeastSigBits();
    }

    @PrePersist
    public void prePersist() {
        // make sure the uuid is set before persisting
        getUuidLeastSigBits();
    }

}

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

আমি আপনার জবাবটি আপ-ভোট দিয়েছি কারণ আমি আপনার অন্যান্য ধারণাগুলি সত্যিই পছন্দ করি: ডাটাবেসটিতে ইউইউডি সংখ্যার জোড় হিসাবে স্টোর করে এবং সমান () পদ্ধতির অভ্যন্তরে কোনও নির্দিষ্ট প্রকারে কাস্টিং না - এটি সত্যিই ঝরঝরে! ভবিষ্যতে আমি অবশ্যই এই দুটি কৌশল ব্যবহার করব।
অ্যান্ড্রু

1
আপ-ভোটের জন্য ধন্যবাদ অলসভাবে ইউইউডি সূচনা করার কারণটি ছিল আমাদের অ্যাপ্লিকেশনটিতে আমরা প্রচুর সত্তা তৈরি করি যা কখনই হ্যাশম্যাপে রাখা হয় না বা স্থায়ী হয় না। সুতরাং আমরা যখন বস্তুটি তৈরি করছিলাম তখন তার কার্যকারিতাটি 100x হ্রাস পেয়েছি (এর মধ্যে 100,000)। সুতরাং আমরা যদি কেবল ইউইউডি প্রয়োজন তবে তা শুরু করি। আমি কেবল চাই যে মাইএসকিউএলে 128 বিট সংখ্যার জন্য ভাল সমর্থন ছিল যাতে আমরা কেবল আইডির জন্য ইউইউডি ব্যবহার করতে পারি এবং অটো_সংশোধনের কোনও যত্ন নেই।
ড্রয়

আচ্ছা বুঝলাম. আমার ক্ষেত্রে আমরা এমনকি ইউইউডি ফিল্ডটি ঘোষণা করি না যদি সংশ্লিষ্ট সত্তা সংগ্রহ করা যায় না। অসুবিধাটি হ'ল আমাদের মাঝে মাঝে এটি যুক্ত করতে হয় কারণ পরে দেখা যায় যে আমাদের আসলে সেগুলি সংগ্রহের মধ্যে রাখা দরকার। এটি কখনও কখনও উন্নয়নের সময় ঘটে তবে ভাগ্যক্রমে কোনও গ্রাহকের কাছে প্রাথমিক স্থাপনার পরে আমাদের সাথে কখনই ঘটেনি তাই এটি কোনও বড় কথা নয়। সিস্টেমটি লাইভ হওয়ার পরে যদি এটি ঘটে তবে আমাদের একটি ডিবি স্থানান্তর দরকার। অলস ইউইউডি এই জাতীয় পরিস্থিতিতে খুব সহায়ক।
অ্যান্ড্রু Листочкин

যদি আপনার পরিস্থিতিতে পারফরম্যান্স একটি জটিল সমস্যা হয় তবে আপনার উত্তরটি দ্রুত ইউআইডি জেনারেটর অ্যাডামকে দেওয়া দ্রুত চেষ্টা করা উচিত।
অ্যান্ড্রু Листочкин

3

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

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

সতর্কতার কথা যদিও: যদি আপনার সত্তাগুলি বিভিন্ন টেবিলগুলিতে সঞ্চিত থাকে এবং আপনার সরবরাহকারী প্রাথমিক কীটির জন্য একটি স্বয়ংক্রিয় প্রজন্মের কৌশল ব্যবহার করেন, তবে সত্তার প্রকারভেদে আপনাকে নকল করা প্রাথমিক কীগুলি পাওয়া যাবে। এই ক্ষেত্রে, অবজেক্ট # getClass () এ কল করার সাথে রান টাইম টাইপগুলিও তুলনা করুন যা অবশ্যই দু'টি ভিন্ন ধরণের সমান বলে বিবেচিত হবে impossible এটি বেশিরভাগ অংশের জন্য আমার পক্ষে উপযুক্ত।


এমনকি কোনও ডিবি অনুপস্থিত ক্রমগুলি (মাইস্কুলের মতো) দিয়েও সেগুলি অনুকরণ করা সম্ভব (যেমন, টেবিল হাইবারনেট_সেক্সেন্স)। সুতরাং আপনি সর্বদা সারণী জুড়ে অনন্য আইডি পেতে পারেন। +++ তবে আপনার এটির দরকার নেই। Object#getClass() এইচ। প্রক্সির কারণে কলিংটি খারাপ। কলিং Hibernate.getClass(o)সাহায্য করে, তবে বিভিন্ন ধরণের সত্তার সমতার সমস্যা থেকে যায়। CanEqual ব্যবহার করে একটি সমাধান রয়েছে , কিছুটা জটিল, তবে ব্যবহারযোগ্য। সম্মত হন যে সাধারণত এটির প্রয়োজন হয় না। +++ নাল আইডিতে একা / এইচসি মধ্যে ছোঁড়া চুক্তি লঙ্ঘন করে তবে এটি খুব বাস্তববাদী।
মার্টিনাস

2

এখানে ইতিমধ্যে ইতিমধ্যে খুব তথ্যমূলক উত্তর আছে তবে আমি আপনাকে যা করব তা আমি আপনাকে জানাব।

আমরা কিছুই করি না (অর্থাৎ ওভাররাইড করি না)।

আমাদের সংগ্রহের জন্য কাজ করার জন্য যদি সমান / হ্যাশকোডের দরকার হয় তবে আমরা ইউইউডি ব্যবহার করি। আপনি কেবল কনস্ট্রাক্টরে ইউআইডি তৈরি করুন। আমরা ইউইউডি-র জন্য http://wiki.fasterxML.com/JugHome ব্যবহার করি । ইউআইডি হ'ল সিপিইউটি একটু বেশি ব্যয়বহুল তবে সিরিয়ালাইজেশন এবং ডিবি অ্যাক্সেসের তুলনায় সস্তা।


1

আমি অতীতে সর্বদা 1 বিকল্পটি ব্যবহার করেছি কারণ আমি এই আলোচনাগুলি সম্পর্কে অবগত ছিলাম এবং ভেবেছিলাম যে যতক্ষণ না সঠিক কাজটি করতে হবে তা না জানা পর্যন্ত কিছুই না করাই ভাল। সেগুলি সমস্ত এখনও সফলতার সাথে চলছে।

যাইহোক, পরের বার আমি বিকল্প 2 - আইডি উত্পন্ন আইডিটি ব্যবহার করে চেষ্টা করতে পারি।

আইডি সেট না করা থাকলে হ্যাশকোড এবং সমতুল্য ইলিজেলস্টেটএক্সেপশন নিক্ষেপ করবে।

এটি সংরক্ষণ না করা সত্তা জড়িত সূক্ষ্ম ত্রুটিগুলি অপ্রত্যাশিতভাবে প্রদর্শিত হতে বাধা দেবে।

লোকেরা এই পদ্ধতির বিষয়ে কী মনে করে?


1

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

  1. ডিবিতে কোনও অতিরিক্ত ক্ষেত্র নেই
  2. বংশধর সত্তাগুলিতে কোনও অতিরিক্ত কোডিং নেই, সবার জন্য একটি পদ্ধতির
  3. কোনও পারফরম্যান্স সমস্যা নেই (যেমন ইউইউডি সহ), ডিবি আইডি জেনারেশন
  4. হাশম্যাপস নিয়ে কোনও সমস্যা নেই (সমান ব্যবহার ইত্যাদি বিবেচনার প্রয়োজন নেই)
  5. স্থির থাকার পরেও নতুন সত্তার হ্যাশকোড সময় পরিবর্তন হয় না

কনস:

  1. অবিচলিত সত্তাগুলি সিরিয়ালকরণ ও deserialization করার ক্ষেত্রে সমস্যা হতে পারে
  2. ডিবি থেকে পুনরায় লোড করার পরে সংরক্ষিত সত্তার হ্যাশকোড পরিবর্তন হতে পারে
  3. অবিচলিত অবজেক্টগুলিকে সর্বদা আলাদা বিবেচনা করা হয় না (সম্ভবত এটি সঠিক?)
  4. আর কি?

আমাদের কোড দেখুন:

@MappedSuperclass
abstract public class Entity implements Serializable {

    @Id
    @GeneratedValue
    @Column(nullable = false, updatable = false)
    protected Long id;

    @Transient
    private Long tempId;

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

    public Long getId() {
        return id;
    }

    private void setTempId(Long tempId) {
        this.tempId = tempId;
    }

    // Fix Id on first call from equal() or hashCode()
    private Long getTempId() {
        if (tempId == null)
            // if we have id already, use it, else use 0
            setTempId(getId() == null ? 0 : getId());
        return tempId;
    }

    @Override
    public boolean equals(Object obj) {
        if (super.equals(obj))
            return true;
        // take proxied object into account
        if (obj == null || !Hibernate.getClass(obj).equals(this.getClass()))
            return false;
        Entity o = (Entity) obj;
        return getTempId() != 0 && o.getTempId() != 0 && getTempId().equals(o.getTempId());
    }

    // hash doesn't change in time
    @Override
    public int hashCode() {
        return getTempId() == 0 ? super.hashCode() : getTempId().hashCode();
    }
}

1

পূর্বনির্ধারিত প্রকার শনাক্তকারী এবং আইডির উপর ভিত্তি করে নীচের পদ্ধতির বিষয়টি বিবেচনা করুন।

জেপিএর জন্য নির্দিষ্ট অনুমান:

  • একই "টাইপ" এবং একই অ-নাল আইডি সত্তাকে সমান হিসাবে বিবেচনা করা হয়
  • অ-অবিচলিত সত্তা (কোনও আইডি অনুমান করে) কখনই অন্যান্য সত্তার সমান হয় না

বিমূর্ত সত্তা:

@MappedSuperclass
public abstract class AbstractPersistable<K extends Serializable> {

  @Id @GeneratedValue
  private K id;

  @Transient
  private final String kind;

  public AbstractPersistable(final String kind) {
    this.kind = requireNonNull(kind, "Entity kind cannot be null");
  }

  @Override
  public final boolean equals(final Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof AbstractPersistable)) return false;
    final AbstractPersistable<?> that = (AbstractPersistable<?>) obj;
    return null != this.id
        && Objects.equals(this.id, that.id)
        && Objects.equals(this.kind, that.kind);
  }

  @Override
  public final int hashCode() {
    return Objects.hash(kind, id);
  }

  public K getId() {
    return id;
  }

  protected void setId(final K id) {
    this.id = id;
  }
}

কংক্রিট সত্তার উদাহরণ:

static class Foo extends AbstractPersistable<Long> {
  public Foo() {
    super("Foo");
  }
}

পরীক্ষার উদাহরণ:

@Test
public void test_EqualsAndHashcode_GivenSubclass() {
  // Check contract
  EqualsVerifier.forClass(Foo.class)
    .suppress(Warning.NONFINAL_FIELDS, Warning.TRANSIENT_FIELDS)
    .withOnlyTheseFields("id", "kind")
    .withNonnullFields("id", "kind")
    .verify();
  // Ensure new objects are not equal
  assertNotEquals(new Foo(), new Foo());
}

এখানে প্রধান সুবিধা:

  • সরলতা
  • সাবক্লাসগুলি ধরণের পরিচয় সরবরাহ নিশ্চিত করে
  • অনুমান শ্রেণীর সাথে আচরণের পূর্বাভাস

অসুবিধা:

  • প্রতিটি সত্তাকে কল করার প্রয়োজন super()

মন্তব্য:

  • উত্তরাধিকার ব্যবহার করার সময় মনোযোগের প্রয়োজন। উদাহরণস্বরূপ সাম্যতা class Aএবং class B extends Aঅ্যাপ্লিকেশনটির কংক্রিট বিশদের উপর নির্ভর করে।
  • আদর্শভাবে, আইডি হিসাবে একটি ব্যবসায়িক কী ব্যবহার করুন

আপনার মন্তব্যের প্রত্যাশায়


0

এটি জাভা এবং জেপিএ ব্যবহার করে এমন প্রতিটি আইটি সিস্টেমে একটি সাধারণ সমস্যা। ব্যথা পয়েন্ট সমান () এবং হ্যাশকোড () প্রয়োগের বাইরেও প্রসারিত, এটি কোনও সংস্থা কীভাবে কোনও সত্তাকে রেফার করে এবং কীভাবে তার ক্লায়েন্টরা একই সত্তাকে বোঝায় তা প্রভাবিত করে। আমি আমার দৃষ্টিভঙ্গি প্রকাশের জন্য নিজের ব্লগটি লিখেছিলাম এমন একটি ব্যবসায়ের কী না হওয়ার যথেষ্ট ব্যথা দেখেছি seen

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


0

আইএমও আপনার কাছে সমান / হ্যাশকোড প্রয়োগের জন্য 3 টি বিকল্প রয়েছে

  • একটি অ্যাপ্লিকেশন উত্পন্ন পরিচয় ব্যবহার করুন যেমন একটি ইউইউডি
  • এটি একটি ব্যবসায়ের কী এর ভিত্তিতে প্রয়োগ করুন
  • প্রাথমিক কী এর উপর ভিত্তি করে এটি প্রয়োগ করুন

একটি অ্যাপ্লিকেশন উত্পন্ন পরিচয় ব্যবহার করা সহজতম পদ্ধতির, তবে কয়েকটি ডাউনসাইড সহ আসে

  • একে পিকে হিসাবে ব্যবহার করার সময় ধীরে ধীরে যোগ দেয় কারণ 128 বিট 32 বা 64 বিটের চেয়ে সহজ
  • "ডিবাগিং শক্ত" কারণ আপনার নিজের চোখের সাথে পরীক্ষা করা অন্য কোনও ডেটা সঠিক বলে প্রমাণ করা বেশ শক্ত

আপনি যদি এই ডাউনসাইডগুলির সাথে কাজ করতে পারেন তবে কেবল এই পদ্ধতির ব্যবহার করুন।

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

@Entity class Parent {
  @Id @GeneratedValue Long id;
  @NaturalId UUID uuid;
  @OneToMany(mappedBy = "parent") Set<Child> children;
  // equals/hashCode based on uuid
}

@Entity class Child {
  @EmbeddedId ChildId id;
  @ManyToOne Parent parent;

  @Embeddable class ChildId {
    UUID parentUuid;
    UUID childUuid;
    // equals/hashCode based on parentUuid and childUuid
  }
  // equals/hashCode based on id
}

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

এটি কোনও ব্যবসায়ের কী এর উপর ভিত্তি করে বাস্তবায়ন করুন যদি আপনি এটির আশা করতে পারেন যে কোনও ব্যবহারকারীর কাছ থেকে এটি একটি দুর্দান্ত ধারণা, তবে কয়েকটি ডাউনসাইড পাশাপাশি আসে

বেশিরভাগ সময় এই ব্যবসায়িক কীটি এমন এক ধরণের কোড হবে যা ব্যবহারকারী সরবরাহ করে এবং কম প্রায়ই একাধিক বৈশিষ্ট্যের সংমিশ্রণ হয়।

  • যোগদানগুলি ধীর হয় কারণ পরিবর্তনশীল দৈর্ঘ্যের পাঠ্যের উপর ভিত্তি করে যোগদান করা কেবল ধীর। কিছু ডিবিএমএস-তে এমনকি কীটি নির্দিষ্ট দৈর্ঘ্য ছাড়িয়ে গেলে সূচি তৈরি করতে সমস্যা হতে পারে।
  • আমার অভিজ্ঞতায়, ব্যবসায়িক কীগুলি পরিবর্তিত হয় যার জন্য এটি উল্লেখ করা অবজেক্টের জন্য ক্যাসকেডিং আপডেটের প্রয়োজন হবে। বাহ্যিক সিস্টেমগুলি যদি এটি উল্লেখ করে তবে এটি অসম্ভব

IMO আপনার একচেটিয়াভাবে কী কী প্রয়োগ করে বা কাজ করা উচিত নয়। এটি একটি দুর্দান্ত অ্যাড-অন অর্থাত্ ব্যবহারকারীরা দ্রুত সেই ব্যবসায়িক কী দ্বারা অনুসন্ধান করতে পারে, তবে অপারেটিংয়ের জন্য সিস্টেমটিকে এটির উপর নির্ভর করা উচিত নয়।

প্রাথমিক কীটির উপর ভিত্তি করে এটি প্রয়োগ করুন এতে সমস্যা আছে তবে এটি এত বড় বিষয় নয়

আপনার যদি বাহ্যিক সিস্টেমে আইডিকে প্রকাশ করতে হয় তবে আমার প্রস্তাবিত ইউআইডি পদ্ধতির ব্যবহার করুন। আপনি যদি তা না করেন তবে আপনি এখনও ইউআইডি পদ্ধতির ব্যবহার করতে পারেন তবে আপনার দরকার নেই। সমান / হ্যাশকোডে একটি ডিবিএমএস উত্পন্ন আইডি ব্যবহার করার সমস্যাটি এই আইডিটি নির্ধারণের আগে হ্যাশ ভিত্তিক সংগ্রহগুলিতে যুক্ত করা যেতে পারে তা থেকে উদ্ভূত হয়।

এর কাছাকাছি যাওয়ার সুস্পষ্ট উপায় হ'ল আইডি নির্ধারণের আগে হ্যাশ ভিত্তিক সংগ্রহগুলিতে কেবলমাত্র বস্তুটি যুক্ত করা নয়। আমি বুঝতে পেরেছি যে এটি সর্বদা সম্ভব নয় কারণ আপনি ইতিমধ্যে আইডি বরাদ্দের আগে নকল করতে চান। এখনও হ্যাশ ভিত্তিক সংগ্রহগুলি ব্যবহার করতে সক্ষম হতে, আপনাকে কেবল আইডি নির্ধারণের পরে সংগ্রহগুলি পুনর্নির্মাণ করতে হবে।

আপনি এরকম কিছু করতে পারেন:

@Entity class Parent {
  @Id @GeneratedValue Long id;
  @OneToMany(mappedBy = "parent") Set<Child> children;
  // equals/hashCode based on id
}

@Entity class Child {
  @EmbeddedId ChildId id;
  @ManyToOne Parent parent;

  @PrePersist void postPersist() {
    parent.children.remove(this);
  }
  @PostPersist void postPersist() {
    parent.children.add(this);
  }

  @Embeddable class ChildId {
    Long parentId;
    @GeneratedValue Long childId;
    // equals/hashCode based on parentId and childId
  }
  // equals/hashCode based on id
}

আমি নিজেই সঠিক পদ্ধতির পরীক্ষা করিনি, সুতরাং আমি নিশ্চিত না যে পূর্বের এবং পরবর্তী-পরবর্তী ইভেন্টগুলিতে সংগ্রহগুলি কীভাবে পরিবর্তন করা যায় তবে ধারণাটিটি হ'ল:

  • অস্থায়ীভাবে হ্যাশ ভিত্তিক সংগ্রহ থেকে অবজেক্টটি সরান
  • এটি অবিরত
  • হ্যাশ ভিত্তিক সংগ্রহগুলিতে অবজেক্টটিকে পুনরায় যুক্ত করুন

এটি সমাধানের আরেকটি উপায় হ'ল কোনও আপডেট / চালিয়ে যাওয়ার পরে আপনার সমস্ত হ্যাশ ভিত্তিক মডেলগুলি কেবল নতুন করে তৈরি করা।

শেষ পর্যন্ত, এটি আপনার উপর নির্ভর করে। আমি ব্যক্তিগতভাবে সিকোয়েন্স ভিত্তিক বেশিরভাগ সময় ব্যবহার করি এবং কেবলমাত্র ইউইউডি পদ্ধতির ব্যবহার করি যদি আমাকে বাহ্যিক সিস্টেমে কোনও সনাক্তকারী প্রকাশ করতে হয় need


0

instanceofজাভা 14 থেকে নতুন স্টাইলের সাহায্যে equalsআপনি এক লাইনে প্রয়োগ করতে পারেন ।

@Override
public boolean equals(Object obj) {
    return this == obj || id != null && obj instanceof User otherUser && id.equals(otherUser.id);
}

@Override
public int hashCode() {
    return 31;
}

-1

যদি ইউইউডি অনেক লোকের উত্তর হয় তবে আমরা কেন সত্ত্বা তৈরি করতে এবং তৈরির সময় প্রাথমিক কী বরাদ্দ করতে ব্যবসায়ের স্তর থেকে কারখানার পদ্ধতিগুলি ব্যবহার করি না?

উদাহরণ স্বরূপ:

@ManagedBean
public class MyCarFacade {
  public Car createCar(){
    Car car = new Car();
    em.persist(car);
    return car;
  }
}

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

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

কীভাবে?


আপনি যদি কোনও ডাটাবেস অনুসন্ধান করার সময় নির্দেশিকা তৈরি করতে উভয় ক্ষেত্রেই পারফরম্যান্স গ্রহণ করতে ইচ্ছুক হন তবে দুর্দান্ত কাজ করে approach
মাইকেল উইলস

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

-1

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

তবে আমি আরও বেশি নমনীয়তা যুক্ত করতে চেয়েছিলাম, অর্থাৎ প্রতিটি সমাধানের সুবিধার সাথে সত্তার প্রথম অধ্যবসায়ের আগে যখন হ্যাশকোড () / সমান () অ্যাক্সেস করা হয় তখন অলস কেবলমাত্র ইউইউডি তৈরি করুন:

  • সমান () এর অর্থ "অবজেক্ট একই লজিক্যাল সত্তাকে বোঝায়"
  • যথাসম্ভব ডাটাবেস আইডি ব্যবহার করুন কারণ আমি কেন কাজটি দু'বার করব (পারফরম্যান্স উদ্বেগ)
  • এখনও অব্যাহত সত্তা সম্পর্কে হ্যাশকোড () / সমান () অ্যাক্সেস করার সময় সমস্যা প্রতিরোধ করুন এবং সত্যই স্থির থাকার পরে একই আচরণ রাখুন

আমি নীচে আমার মিশ্র সমাধানে প্রতিক্রিয়া সত্যই স্বীকার করব

public class MyEntity { 

    @Id()
    @Column(name = "ID", length = 20, nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id = null;

    @Transient private UUID uuid = null;

    @Column(name = "UUID_MOST", nullable = true, unique = false, updatable = false)
    private Long uuidMostSignificantBits = null;
    @Column(name = "UUID_LEAST", nullable = true, unique = false, updatable = false)
    private Long uuidLeastSignificantBits = null;

    @Override
    public final int hashCode() {
        return this.getUuid().hashCode();
    }

    @Override
    public final boolean equals(Object toBeCompared) {
        if(this == toBeCompared) {
            return true;
        }
        if(toBeCompared == null) {
            return false;
        }
        if(!this.getClass().isInstance(toBeCompared)) {
            return false;
        }
        return this.getUuid().equals(((MyEntity)toBeCompared).getUuid());
    }

    public final UUID getUuid() {
        // UUID already accessed on this physical object
        if(this.uuid != null) {
            return this.uuid;
        }
        // UUID one day generated on this entity before it was persisted
        if(this.uuidMostSignificantBits != null) {
            this.uuid = new UUID(this.uuidMostSignificantBits, this.uuidLeastSignificantBits);
        // UUID never generated on this entity before it was persisted
        } else if(this.getId() != null) {
            this.uuid = new UUID(this.getId(), this.getId());
        // UUID never accessed on this not yet persisted entity
        } else {
            this.setUuid(UUID.randomUUID());
        }
        return this.uuid; 
    }

    private void setUuid(UUID uuid) {
        if(uuid == null) {
            return;
        }
        // For the one hypothetical case where generated UUID could colude with UUID build from IDs
        if(uuid.getMostSignificantBits() == uuid.getLeastSignificantBits()) {
            throw new Exception("UUID: " + this.getUuid() + " format is only for internal use");
        }
        this.uuidMostSignificantBits = uuid.getMostSignificantBits();
        this.uuidLeastSignificantBits = uuid.getLeastSignificantBits();
        this.uuid = uuid;
    }

"আমি চালিয়ে যাওয়ার আগে এই সত্তায় একদিন ইউইউডি উত্পন্ন হয়েছিল" বলতে কী বোঝ? আপনি দয়া করে এই ক্ষেত্রে একটি উদাহরণ দিতে পারেন?
jhegedus

আপনি নির্ধারিত প্রজন্মের ধরন ব্যবহার করতে পারেন? পরিচয় প্রজন্মের ধরণের দরকার কেন? বরাদ্দ দেওয়া এর কিছু সুবিধা আছে?
heেগেদাস

আপনি যদি 1) একটি নতুন মাইএনটিটি তৈরি করেন, 2) এটি একটি তালিকায় রাখুন, 3) এটি ডাটাবেসে সংরক্ষণ করুন তারপর 4) আপনি সেই সত্ত্বাকে ডিবি থেকে আবার লোড করুন এবং 5) বোঝা উদাহরণটি তালিকায় রয়েছে কিনা তা দেখার চেষ্টা করুন । আমার ধারণা এটি হওয়া সত্ত্বেও তা হবে না।
heেগেদাস

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

-1

অনুশীলনে মনে হয়, বিকল্প 2 (প্রাথমিক কী) সর্বাধিক ব্যবহৃত হয়। প্রাকৃতিক এবং অপ্রত্যাশিত ব্যবসায়ের কী খুব কমই হয়, সিন্থেটিক কী তৈরি করা এবং সমর্থন করা পরিস্থিতি সমাধানে খুব ভারী, যা সম্ভবত কখনও হয় নি। কটাক্ষপাত আছে বসন্ত-ডেটা-jpa AbstractPersistable (: শুধুমাত্র জিনিস বাস্তবায়ন হাইবারনেট বাস্তবায়ন ব্যবহারের জন্যHibernate.getClass )।

public boolean equals(Object obj) {
    if (null == obj) {
        return false;
    }
    if (this == obj) {
        return true;
    }
    if (!getClass().equals(ClassUtils.getUserClass(obj))) {
        return false;
    }
    AbstractPersistable<?> that = (AbstractPersistable<?>) obj;
    return null == this.getId() ? false : this.getId().equals(that.getId());
}

@Override
public int hashCode() {
    int hashCode = 17;
    hashCode += null == getId() ? 0 : getId().hashCode() * 31;
    return hashCode;
}

হ্যাশসেট / হ্যাশম্যাপে নতুন অবজেক্টগুলি চালিত করার বিষয়ে কেবল সচেতন। বিপরীতে, বিকল্প 1 ( Objectবাস্তবায়ন অব্যাহত রাখা ) এর ঠিক পরে ভেঙে গেছে merge, এটি খুব সাধারণ পরিস্থিতি।

আপনার যদি কোনও ব্যবসায়ের কী না থাকে এবং হ্যাশ স্ট্রাকচারে নতুন সত্তাকে হস্তান্তর করার জন্য সত্যিকারের প্রয়োজন হয় তবে hashCodeনীচের দিকে ভ্লাদ মিহালসিয়াকে পরামর্শ দেওয়া হয়েছিল constant


-2

নীচে স্কালার জন্য একটি সহজ (এবং পরীক্ষিত) সমাধান রয়েছে।

  • দ্রষ্টব্য যে এই সমাধানটি প্রশ্নের মধ্যে দেওয়া 3 টি বিভাগের কোনওটির সাথে খাপ খায় না।

  • আমার সমস্ত সত্তা ইউইউডিইটিটির সাবক্লাস তাই আমি নিজেকে পুনর্বার-পুনরাবৃত্তি (ডিআরওয়াই) নীতি অনুসরণ করি।

  • প্রয়োজনে ইউআইডি প্রজন্মকে আরও সুনির্দিষ্ট করা যায় (আরও সিউডো-এলোমেলো নম্বর ব্যবহার করে)।

স্কাল কোড:

import javax.persistence._
import scala.util.Random

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
abstract class UUIDEntity {
  @Id  @GeneratedValue(strategy = GenerationType.TABLE)
  var id:java.lang.Long=null
  var uuid:java.lang.Long=Random.nextLong()
  override def equals(o:Any):Boolean= 
    o match{
      case o : UUIDEntity => o.uuid==uuid
      case _ => false
    }
  override def hashCode() = uuid.hashCode()
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.