আমি কীভাবে স্প্রিং-ডেটা-জেপিএ ব্যবহার করে কোনও সত্তাকে আপডেট করব?


194

ওয়েল প্রশ্ন বেশ কিছু বলেন। জেআরপোসিটোরি ব্যবহার করে কীভাবে আমি কোনও সত্তা আপডেট করব?

জর্পোপোসিটোরিতে কেবল একটি সংরক্ষণের পদ্ধতি রয়েছে যা এটি আসলে তৈরি বা আপডেট হয় কিনা তা আমাকে জানায় না। উদাহরণস্বরূপ, আমি ডাটাবেসের ব্যবহারকারী, যা তিনটি ক্ষেত্র রয়েছে একটি সহজ অবজেক্ট ঢোকান: firstname, lastnameএবং age:

 @Entity
 public class User {

  private String firstname;
  private String lastname;
  //Setters and getters for age omitted, but they are the same as with firstname and lastname.
  private int age;

  @Column
  public String getFirstname() {
    return firstname;
  }
  public void setFirstname(String firstname) {
    this.firstname = firstname;
  }

  @Column
  public String getLastname() {
    return lastname;
  }
  public void setLastname(String lastname) {
    this.lastname = lastname;
  }

  private long userId;

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  public long getUserId(){
    return this.userId;
  }

  public void setUserId(long userId){
    this.userId = userId;
  }
}

তারপরে আমি কেবল কল করি save()যা এই মুহুর্তে আসলে ডাটাবেসে একটি সন্নিবেশ:

 User user1 = new User();
 user1.setFirstname("john"); user1.setLastname("dew");
 user1.setAge(16);

 userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);

এ পর্যন্ত সব ঠিকই. এখন আমি এই ব্যবহারকারীকে আপডেট করতে চাই, বলুন তার বয়স পরিবর্তন করুন। এই উদ্দেশ্যে আমি কোয়েরিএসডিএল বা নেমডকুইয়ারি, যাই হোক না কেন, একটি প্রশ্ন ব্যবহার করতে পারি। তবে, আমি কেবল স্প্রিং-ডেটা-জেপিএ এবং জেআরএপোসিটোরি ব্যবহার করতে চাই তা বিবেচনা করে আমি কীভাবে এটি বলব যে একটি সন্নিবেশের পরিবর্তে আমি একটি আপডেট করতে চাই?

বিশেষত, আমি কীভাবে স্প্রিং-ডেটা-জেপাকে বলব যে একই ব্যবহারকারীর নাম এবং প্রথম নাম ব্যবহারকারীরাই আসলে একুয়াল এবং বিদ্যমান সত্তাটি আপডেট হওয়ার কথা? ওভাররাইডিং সমান এই সমস্যাটির সমাধান করেনি।


1
আপনি কি নিশ্চিত যে আপনি যখন ডাটাবেসে কোনও বিদ্যমান বস্তুটি সংরক্ষণ করেন তখন আইডিটি পুনরায় লেখা হবে ?? আমার প্রজেক্ট
টিবিএইচটিতে

@ বায়রন ভার্বাচ হ্যাঁ আপনি ঠিক বলেছেন, ঠিক এটি পরীক্ষা করেছেন। প্রশ্নটিও আপডেট করুন, থেক্স
ইউজিন

2
হ্যালো বন্ধু, আপনি যদি এই লিঙ্কটি সন্ধান করতে পারেন stackoverflow.com/questions/24420572/... আপনি saveOrUpdate () মত একটি পদ্ধতির হতে পারে
ibrahimKiraz


আমি মনে করি আমাদের এখানে একটি সুন্দর সমাধান রয়েছে: লিঙ্কের বিবরণটি এখানে লিখুন
ক্লিবিও ভিয়েরা

উত্তর:


207

সত্তা সনাক্তকরণ তাদের প্রাথমিক কী দ্বারা সংজ্ঞায়িত করা হয়। যেহেতু firstnameএবং lastnameপ্রাথমিক কী অংশগুলি নন, আপনি চিকিত্সার জন্য JPA বলতে পারে না Userএকই সঙ্গে গুলি firstnames এবং lastnameসমান হিসাবে গুলি যদি তারা বিভিন্ন আছে userIdসে।

সুতরাং, আপনি একটি আপডেট করতে চান Userতার দ্বারা চিহ্নিত firstnameএবং lastname, আপনি যে বের করতে হবে Userএকটি ক্যোয়ারী দ্বারা, এবং তারপর বস্তুর উপযুক্ত ক্ষেত্র পরিবর্তন আপনার খুঁজে পাওয়া যায়নি। এই পরিবর্তনগুলি লেনদেনের শেষে স্বয়ংক্রিয়ভাবে ডাটাবেসে ফ্লাশ হয়ে যাবে, যাতে এই পরিবর্তনগুলি স্পষ্টভাবে সংরক্ষণ করার জন্য আপনাকে কিছু করার দরকার নেই।

সম্পাদনা করুন:

সম্ভবত আমার জেপিএর সামগ্রিক শব্দার্থবিজ্ঞানের বিস্তারিত বলা উচিত। দৃ pers়তা API গুলি ডিজাইনের জন্য দুটি প্রধান পন্থা রয়েছে:

  • সন্নিবেশ / আপডেট পদ্ধতির । আপনার যখন ডাটাবেসটি সংশোধন করতে হবে তখন আপনাকে দৃ API়তার সাথে এপিআইয়ের পদ্ধতিগুলি স্পষ্টভাবে কল insertকরতে হবে : আপনি কোনও বস্তু সন্নিবেশ updateকরার জন্য , বা ডাটাবেজে অবজেক্টের নতুন অবস্থার সংরক্ষণ করতে কল করেছেন।

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

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


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

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

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

1
এটি আমার পক্ষে কাজ করবে না। আমি একটি বৈধ প্রাথমিক কী সহ কোনও সত্তাকে সঞ্চয় করার চেষ্টা করেছি। আমি পৃষ্ঠাটি "অর্ডার / সম্পাদনা /: আইডি" দিয়ে অ্যাক্সেস করি এবং এটি আসলে আইডির মাধ্যমে আমাকে সঠিক অবজেক্ট দেয়। আমি Godশ্বরের ভালবাসার জন্য চেষ্টা করি না কিছুই সত্তা আপডেট করবে। এটি সর্বদা একটি নতুন সত্তা পোস্ট করে .. আমি এমনকি নিজের স্বত্ব ম্যানেজারের সাথে একটি কাস্টম পরিষেবা তৈরি করার এবং "মার্জ" ব্যবহার করার চেষ্টা করেছি এবং এটি এখনও কাজ করবে না। এটি সর্বদা একটি নতুন সত্তা পোস্ট করবে।
DtechNet

1
@ ডিটেকনেট, ডেটেকনেট আমি আপনার কাছে একইরকম সমস্যাটি অনুভব করছিলাম এবং আমার সমস্যাটি প্রমাণিত হয়েছিল যে আমার স্প্রিং ডেটা সংগ্রহস্থল ইন্টারফেসে উল্লিখিত ভুল প্রাথমিক কী টাইপ ছিল had এটি বলেছে extends CrudRepository<MyEntity, Integer>পরিবর্তে extends CrudRepository<MyEntity, String>এটি করা উচিত। এটা কি সাহায্য করে? আমি জানি এটি প্রায় এক বছর পরে। আশা করি এটি অন্য কাউকে সাহায্য করবে।
কেন্ট বুল

139

যেহেতু @axtavt দ্বারা উত্তর উপর গুরুত্ত্ব দেয় JPAনাspring-data-jpa

কোয়েরি করে কোনও সত্তা আপডেট করার জন্য সংরক্ষণ করা কার্যকর নয় কারণ এর জন্য দুটি প্রশ্নের প্রয়োজন এবং সম্ভবত ক্যোয়ারীটি ব্যয়বহুল হতে পারে কারণ এটি অন্যান্য সারণীতে যোগ দিতে পারে এবং যে কোনও সংগ্রহ রয়েছে তা লোড করতে পারে fetchType=FetchType.EAGER

Spring-data-jpaআপডেট অপারেশন সমর্থন করে।
আপনি সংগ্রহস্থলের মধ্যে পদ্ধতি সঙ্গে এটি সটীক interface.and সংজ্ঞায়িত আছে @Queryএবং @Modifying

@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);

@Queryকাস্টম ক্যোয়ারী সংজ্ঞা জন্য এবং @Modifyingবলার জন্য নয় spring-data-jpaযে এই প্রশ্নের সাথে একটি আপডেট অপারেশন হয় এবং এটি প্রয়োজন executeUpdate()না executeQuery()

আপনি অন্যান্য রিটার্নের ধরণগুলি নির্দিষ্ট করতে পারেন:
int- রেকর্ডের আপডেট হওয়া সংখ্যা।
boolean- সত্য যদি কোনও রেকর্ড আপডেট করা হচ্ছে। অন্যথায়, মিথ্যা।


দ্রষ্টব্য : একটি লেনদেনে এই কোডটি চালান ।


10
নিশ্চিত হয়ে নিন যে আপনি এটি লেনদেনে
চালাচ্ছেন

1
হে! ধন্যবাদ বসন্ত তথ্য মটরশুটি ব্যবহার করছি। সুতরাং এটি স্বয়ংক্রিয়ভাবে আমার আপডেটের যত্ন নেবে। <এস প্রসারিত টি> এস সেভ (এস সত্তা); স্বয়ংক্রিয়ভাবে আপডেটের যত্ন নেয়। আমি আপনার পদ্ধতি ব্যবহার করতে হবে না! যাইহোক, ধন্যবাদ!
bks4line

3
যে কোনও সময় :) সংরক্ষণের পদ্ধতিটি কার্যকর হয় যদি আপনি সত্তাটি সংরক্ষণ করতে চান (এটি কলটি em.persist () বা em. विसর () দৃশ্যের পিছনে স্থান দেবে)। যাইহোক, আপনি যখন ডাটাবেসে কিছু ক্ষেত্র আপডেট করতে চান তবে কাস্টম ক্যোরিটি কার্যকর।
হুশছাই

আপনার পরামিতিগুলির একটি যখন উপ সত্তার আইডি হয় তখন (বহুগুলি) কীভাবে এটি আপডেট করা উচিত? (বইয়ের একজন লেখক রয়েছে এবং আপনি বইয়ের লেখক আপডেট করতে বইয়ের আইডি এবং লেখক আইডি পাস করেছেন)
মাহদী

1
To update an entity by querying then saving is not efficientএগুলি কেবল দুটি পছন্দ নয়। আইডি নির্দিষ্ট করার এবং সন্ধানের বিষয়টিকে জিজ্ঞাসা না করে পাওয়ার একটি উপায় রয়েছে। আপনি যদি কিছু করেন row = repo.getOne(id)এবং row.attr = 42; repo.save(row);লগগুলি দেখুন, আপনি কেবল আপডেটের ক্যোয়ারী দেখতে পাবেন।
নুরেটিন

21

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

public void updateUser(Userinfos u) {
    User userFromDb = userRepository.findById(u.getid());
    // crush the variables of the object found
    userFromDb.setFirstname("john"); 
    userFromDb.setLastname("dew");
    userFromDb.setAge(16);
    userRepository.save(userFromDb);
}

4
আপডেট করার আগে আপনাকে ডাটাবেস থেকে বস্তুটি লোড করতে হলে পারফরম্যান্সে কোনও সমস্যা হয় না? (আমার
ইংরাজির

3
একটির পরিবর্তে দুটি জিজ্ঞাসা রয়েছে, যা খুব বেশি প্রিফার্ড হয় না
টিগ্রান বাবাজনায়ান

আমি জানি আমি ন্যায়সঙ্গত করতে অন্য পদ্ধতি দেখিয়েছি! তবে আইডি একই হলে জেপিএ কেন আপডেট ফাংশনটি বাস্তবায়িত করেছিল?
কালিফোর্নিয়াম

17

অন্যদের দ্বারা ইতিমধ্যে যা উল্লেখ করা হয়েছে, save()নিজেই ক্রিয়াকলাপ এবং আপডেট অপারেশন উভয়ই রয়েছে।

আমি কেবল save()পদ্ধতির পিছনে কী সম্পর্কে পরিপূরক যোগ করতে চাই ।

প্রথমত, আসুন আমরা এর বর্ধিত স্তরক্রমকে প্রসারিত / প্রয়োগ করি CrudRepository<T,ID>, এখানে চিত্র বর্ণনা লিখুন

ঠিক আছে, আসুন এখানে save()বাস্তবায়ন পরীক্ষা করে দেখুন SimpleJpaRepository<T, ID>,

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

যেমন আপনি দেখতে পাচ্ছেন, এটি আইডিটি বিদ্যমান কিনা তা আগে যাচাই করা হবে, সত্তা ইতিমধ্যে উপস্থিত থাকলে কেবলমাত্র merge(entity)পদ্ধতি দ্বারা আপডেট হবে এবং অন্যথায়, পদ্ধতি দ্বারা একটি নতুন রেকর্ড সন্নিবেশ করা হয়েছে persist(entity)


7

স্প্রিং-ডেটা- save()জেপিএ ব্যবহার করে , আমার @ ডিটেকনেটের মতো সমস্যা ছিল। আমার অর্থ প্রতিটি save()আপডেটের পরিবর্তে নতুন নতুন বস্তু তৈরি করছিল। এটি সমাধান করার জন্য আমাকে versionসত্তা এবং সম্পর্কিত সারণিতে ক্ষেত্র যুক্ত করতে হয়েছিল।


সত্তা এবং সম্পর্কিত সারণিতে সংস্করণ ক্ষেত্র যুক্ত করার অর্থ কী।
jcrshankar


5

এইভাবেই আমি সমস্যার সমাধান করেছি:

User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);

@Transactionবিভিন্ন ডিবি অনুরোধের জন্য উপরের পদ্ধতিটি ব্যবহার করুন । এই ক্ষেত্রে কোনও দরকার নেই userRepository.save(inbound);, পরিবর্তনগুলি স্বয়ংক্রিয়ভাবে ফ্লাশ হয়।
গ্রিগরি কিসলিন

5

বসন্তের ডেটা save()পদ্ধতি আপনাকে উভয়ই সম্পাদন করতে সহায়তা করবে: নতুন আইটেম যুক্ত করা এবং একটি বিদ্যমান আইটেম আপডেট করা।

শুধু কল করুন save()এবং জীবন উপভোগ করুন :))


এইভাবে উপরে যদি আমি আলাদাভাবে প্রেরণ করি তবে Idএটি সংরক্ষণ করবে, কীভাবে আমি নতুন রেকর্ড সংরক্ষণ করতে পারি না।
আবদ আবুগজালেহ

1
@ আবদআবুঝাজালেহ আপনার ইনপোজিস্টরিতে আগত আইডির উপস্থিতি আছে কিনা তা যাচাই করুন। আপনি 'repository.findById (id) .map (সত্তা -> {// কিছু করুন repository.save (সত্তা)}) .orElseGet (() -> {// কিছু ফিরুন;}) ব্যবহার করতে পারেন; '
আমির এমএইচপি

1
public void updateLaserDataByHumanId(String replacement, String humanId) {
    List<LaserData> laserDataByHumanId = laserDataRepository.findByHumanId(humanId);
    laserDataByHumanId.stream()
            .map(en -> en.setHumanId(replacement))
            .collect(Collectors.toList())
            .forEach(en -> laserDataRepository.save(en));
}

@ জোশুয়া টেইলর সত্যিই মিস করেছেন :) মন্তব্যটি সরিয়ে দেবে ...
ইউজিন

1

বিশেষত আমি কীভাবে স্প্রিং-ডেটা-জেপাকে বলব যে একই ব্যবহারকারীর নাম এবং প্রথম নাম রয়েছে এমন ব্যবহারকারীরা আসলে একুয়াল এবং এটি সত্তাটি আপডেট করার কথা। ওভাররাইডিং সমান কাজ করে নি।

এই নির্দিষ্ট উদ্দেশ্যে যে কেউ এই জাতীয়ভাবে একটি যৌগিক কী প্রবর্তন করতে পারে:

CREATE TABLE IF NOT EXISTS `test`.`user` (
  `username` VARCHAR(45) NOT NULL,
  `firstname` VARCHAR(45) NOT NULL,
  `description` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`username`, `firstname`))

ম্যাপিং:

@Embeddable
public class UserKey implements Serializable {
    protected String username;
    protected String firstname;

    public UserKey() {}

    public UserKey(String username, String firstname) {
        this.username = username;
        this.firstname = firstname;
    }
    // equals, hashCode
}

এটি কীভাবে ব্যবহার করবেন তা এখানে:

@Entity
public class UserEntity implements Serializable {
    @EmbeddedId
    private UserKey primaryKey;

    private String description;

    //...
}

জেপাআরপোসিটোরির মতো দেখতে হবে:

public interface UserEntityRepository extends JpaRepository<UserEntity, UserKey>

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

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