एंड्रॉइड रूम - ऑटो-जनरेट के साथ नई सम्मिलित पंक्ति की आईडी प्राप्त करें


138

यह मैं कक्ष दृढ़ता पुस्तकालय का उपयोग कर डेटाबेस में डेटा सम्मिलित कर रहा हूं:

निकाय:

@Entity
class User {
    @PrimaryKey(autoGenerate = true)
    public int id;
    //...
}

डेटा एक्सेस ऑब्जेक्ट:

@Dao
public interface UserDao{
    @Insert(onConflict = IGNORE)
    void insertUser(User user);
    //...
}

एक अलग चयन क्वेरी लिखने के बिना, उपरोक्त विधि में प्रविष्टि पूरी हो जाने के बाद क्या उपयोगकर्ता की आईडी वापस करना संभव है?


1
क्या आपने ऑपरेशन के परिणामस्वरूप उपयोग करने के बजाय intया longइसके बजाय कोशिश की है ? void@Insert
MatPag

अभी नहीं। मैं एक शॉट दूंगा!
SpiralDev

मैंने एक उत्तर इसलिए भी जोड़ा है क्योंकि मुझे प्रलेखन में संदर्भ मिल गया है और मुझे पूरा विश्वास है कि यह काम करेगा;)
MatPag

3
यह एक के साथ नहीं किया जाएगा aSyncTask? आप अपने रिपॉजिटरी फ़ंक्शन से मान कैसे लौटा रहे हैं?
निमित्ज 14

जवाबों:


191

यहाँ प्रलेखन के आधार पर (कोड स्निपेट के नीचे)

@Insertएनोटेशन के साथ एनोटेट की गई विधि वापस आ सकती है:

  • long एकल सम्मिलित ऑपरेशन के लिए
  • long[]या Long[]याList<Long> एकाधिक डालने के संचालन के लिए
  • void यदि आप सम्मिलित आईडी के बारे में परवाह नहीं करते हैं

4
प्रलेखन में यह आईडी प्रकार के लिए int क्यों कहता है, लेकिन लंबे समय तक रिटर्न देता है? मान लिया गया है कि आईडी कभी भी बड़ी नहीं होगी? तो पंक्ति आईडी और ऑटो जनरेट आईडी वास्तव में एक ही बात कर रहे हैं?
माइकल वेस्कोवो

11
SQLite में सबसे बड़ी प्राथमिक कुंजी आईडी आपके पास 64 बिट हस्ताक्षरित पूर्णांक हो सकती है, इसलिए अधिकतम मूल्य 9,223,372,036,854,775,807 (केवल सकारात्मक है क्योंकि यह एक आईडी है)। जावा में एक इंट 32 बिट हस्ताक्षरित संख्या है और अधिकतम सकारात्मक मूल्य 2,147,483,647 है, इसलिए सभी आईडी का प्रतिनिधित्व करने में सक्षम नहीं है। आपको एक जावा लंबे समय का उपयोग करने की आवश्यकता है, जिसका अधिकतम मूल्य सभी आईडी का प्रतिनिधित्व करने के लिए 9,223,372,036,854,775,807 है। प्रलेखन केवल उदाहरण के लिए है, लेकिन एपीआई को इसे ध्यान में रखकर डिजाइन किया गया था (इसीलिए यह लंबे समय तक नहीं लौट रहा और इंट या डबल नहीं)
MatPag

2
ठीक है तो यह वास्तव में एक लंबा होना चाहिए। लेकिन हो सकता है कि ज्यादातर मामलों में एक sqlite db में 9 बिलियन पंक्तियाँ न हों, इसलिए वे userId के लिए एक उदाहरण के रूप में int का उपयोग करते हैं क्योंकि यह कम मेमोरी लेता है (या यह एक गलती है)। यही मैं इससे लेता हूं। यह स्पष्टीकरण के लिए धन्यवाद कि यह लंबे समय तक क्यों लौटता है।
माइकल वेस्कोवो

3
आप सही हैं, लेकिन रूम के एपीआई को सबसे खराब स्थिति में भी काम करना चाहिए और SQlite के विनिर्देशों का पालन करना चाहिए। इस विशिष्ट मामले के लिए लंबे समय तक एक इंट का उपयोग करना व्यावहारिक रूप से एक ही बात है, अतिरिक्त मेमोरी की खपत नगण्य है
MatPag

1
@MatPag आपके मूल लिंक में अब इस व्यवहार की पुष्टि नहीं है (और दुख की बात है, न तो कमरे के सम्मिलित एनोटेशन के लिए एपीआई संदर्भ है )। थोड़ी खोज के बाद मैंने यह पाया और आपके उत्तर में लिंक को अपडेट किया। उम्मीद है कि यह बनी रहती है एक छोटे से पिछले एक की तुलना में बेहतर रूप में इस जानकारी का एक बहुत महत्वपूर्ण बिट है।
CodeClown42

27

@Insertसमारोह लौट सकते हैं void, long, long[]या List<Long>। कृपया यह प्रयास करें।

 @Insert(onConflict = OnConflictStrategy.REPLACE)
  long insert(User user);

 // Insert multiple items
 @Insert(onConflict = OnConflictStrategy.REPLACE)
  long[] insert(User... user);

5
return Single.fromCallable(() -> dbService.YourDao().insert(mObject));
बजे

8

एक रिकॉर्ड के लिए सम्मिलन का वापसी मूल्य 1 होगा यदि आपका कथन सफलतापूर्वक।

यदि आप वस्तुओं की सूची सम्मिलित करना चाहते हैं, तो आप इसके साथ जा सकते हैं:

@Insert(onConflict = OnConflictStrategy.REPLACE)
public long[] addAll(List<Object> list);

और इसे Rx2 के साथ निष्पादित करें:

Observable.fromCallable(new Callable<Object>() {
        @Override
        public Object call() throws Exception {
            return yourDao.addAll(list<Object>);
        }
    }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Consumer<Object>() {
        @Override
        public void accept(@NonNull Object o) throws Exception {
           // the o will be Long[].size => numbers of inserted records.

        }
    });

1
"एक रिकॉर्ड के लिए प्रविष्टि का वापसी मूल्य 1 होगा यदि आपका बयान सफलतापूर्वक" -> इस प्रलेखन के अनुसार: डेवलपर .android.com/training/data-storage/room/accessing-data "यदि @ खोज विधि केवल आदि 1 पैरामीटर, यह एक लंबा रिटर्न दे सकता है, जो सम्मिलित आइटम के लिए नई पंक्ति है। यदि पैरामीटर एक सरणी या संग्रह है, तो इसके बजाय लंबे समय तक वापस लौटना चाहिए [] या सूची <लंबी> । "
कोडक्लोउन42

4

निम्नलिखित स्निपलेट द्वारा पंक्ति ID प्राप्त करें। यह फ्यूचर के साथ एक्जिक्यूटर सर्विस पर कॉल करने योग्य का उपयोग करता है।

 private UserDao userDao;
 private ExecutorService executorService;

 public long insertUploadStatus(User user) {
    Callable<Long> insertCallable = () -> userDao.insert(user);
    long rowId = 0;

    Future<Long> future = executorService.submit(insertCallable);
     try {
         rowId = future.get();
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    return rowId;
 }

Ref: जावा निष्पादनकर्ता सेवा ट्यूटोरियल पर कॉल करने योग्य के बारे में अधिक जानकारी के लिए।


3

आपके Dao में, क्वेरी क्वेरी रिटर्न Longयानी rowId डाला गया।

 @Insert(onConflict = OnConflictStrategy.REPLACE)
 fun insert(recipes: CookingRecipes): Long

आपके मॉडल (रिपॉजिटरी) वर्ग में: (MVVM)

fun addRecipesData(cookingRecipes: CookingRecipes): Single<Long>? {
        return Single.fromCallable<Long> { recipesDao.insertManual(cookingRecipes) }
}

अपने ModelView वर्ग में: (MVVM) डिस्पोजेबलसिंघलऑब्जर्वर के साथ हैंडल लाइवडाटा।
काम करने वाला खट्टा संदर्भ: https://github.com/SupriyaNaveen/CookingRecipes


1

काफी संघर्ष के बाद, मैं इसे हल करने में कामयाब रहा। यहाँ MMVM वास्तुकला का उपयोग करके मेरा समाधान है :

Student.kt

@Entity(tableName = "students")
data class Student(
    @NotNull var name: String,
    @NotNull var password: String,
    var subject: String,
    var email: String

) {

    @PrimaryKey(autoGenerate = true)
    var roll: Int = 0
}

StudentDao.kt

interface StudentDao {
    @Insert
    fun insertStudent(student: Student) : Long
}

StudentRepository.kt

    class StudentRepository private constructor(private val studentDao: StudentDao)
    {

        fun getStudents() = studentDao.getStudents()

        fun insertStudent(student: Student): Single<Long>? {
            return Single.fromCallable(
                Callable<Long> { studentDao.insertStudent(student) }
            )
        }

 companion object {

        // For Singleton instantiation
        @Volatile private var instance: StudentRepository? = null

        fun getInstance(studentDao: StudentDao) =
                instance ?: synchronized(this) {
                    instance ?: StudentRepository(studentDao).also { instance = it }
                }
    }
}

StudentViewModel.kt

class StudentViewModel (application: Application) : AndroidViewModel(application) {

var status = MutableLiveData<Boolean?>()
private var repository: StudentRepository = StudentRepository.getInstance( AppDatabase.getInstance(application).studentDao())
private val disposable = CompositeDisposable()

fun insertStudent(student: Student) {
        disposable.add(
            repository.insertStudent(student)
                ?.subscribeOn(Schedulers.newThread())
                ?.observeOn(AndroidSchedulers.mainThread())
                ?.subscribeWith(object : DisposableSingleObserver<Long>() {
                    override fun onSuccess(newReturnId: Long?) {
                        Log.d("ViewModel Insert", newReturnId.toString())
                        status.postValue(true)
                    }

                    override fun onError(e: Throwable?) {
                        status.postValue(false)
                    }

                })
        )
    }
}

फ्रैगमेंट में:

class RegistrationFragment : Fragment() {
    private lateinit var dataBinding : FragmentRegistrationBinding
    private val viewModel: StudentViewModel by viewModels()

 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initialiseStudent()
        viewModel.status.observe(viewLifecycleOwner, Observer { status ->
            status?.let {
                if(it){
                    Toast.makeText(context , "Data Inserted Sucessfully" , Toast.LENGTH_LONG).show()
                    val action = RegistrationFragmentDirections.actionRegistrationFragmentToLoginFragment()
                    Navigation.findNavController(view).navigate(action)
                } else
                    Toast.makeText(context , "Something went wrong" , Toast.LENGTH_LONG).show()
                //Reset status value at first to prevent multitriggering
                //and to be available to trigger action again
                viewModel.status.value = null
                //Display Toast or snackbar
            }
        })

    }

    fun initialiseStudent() {
        var student = Student(name =dataBinding.edName.text.toString(),
            password= dataBinding.edPassword.text.toString(),
            subject = "",
            email = dataBinding.edEmail.text.toString())
        dataBinding.viewmodel = viewModel
        dataBinding.student = student
    }
}

मैंने DataBinding का उपयोग किया है। मेरा XML है:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

        <variable
            name="student"
            type="com.kgandroid.studentsubject.data.Student" />

        <variable
            name="listener"
            type="com.kgandroid.studentsubject.view.RegistrationClickListener" />

        <variable
            name="viewmodel"
            type="com.kgandroid.studentsubject.viewmodel.StudentViewModel" />

    </data>


    <androidx.core.widget.NestedScrollView
        android:id="@+id/nestedScrollview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        tools:context="com.kgandroid.studentsubject.view.RegistrationFragment">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/constarintLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:isScrollContainer="true">

            <TextView
                android:id="@+id/tvRoll"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:gravity="center_horizontal"
                android:text="Roll : 1"
                android:textColor="@color/colorPrimary"
                android:textSize="18sp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <EditText
                android:id="@+id/edName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="Name"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tvRoll" />

            <TextView
                android:id="@+id/tvName"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:layout_marginEnd="16dp"
                android:text="Name:"
                android:textColor="@color/colorPrimary"
                android:textSize="18sp"
                app:layout_constraintBaseline_toBaselineOf="@+id/edName"
                app:layout_constraintEnd_toStartOf="@+id/edName"
                app:layout_constraintStart_toStartOf="parent" />

            <TextView
                android:id="@+id/tvEmail"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Email"
                android:textColor="@color/colorPrimary"
                android:textSize="18sp"
                app:layout_constraintBaseline_toBaselineOf="@+id/edEmail"
                app:layout_constraintEnd_toStartOf="@+id/edEmail"
                app:layout_constraintStart_toStartOf="parent" />

            <EditText
                android:id="@+id/edEmail"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="Name"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/edName" />

            <TextView
                android:id="@+id/textView6"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Password"
                android:textColor="@color/colorPrimary"
                android:textSize="18sp"
                app:layout_constraintBaseline_toBaselineOf="@+id/edPassword"
                app:layout_constraintEnd_toStartOf="@+id/edPassword"
                app:layout_constraintStart_toStartOf="parent" />

            <EditText
                android:id="@+id/edPassword"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="16dp"
                android:ems="10"
                android:inputType="textPersonName"
                android:text="Name"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/edEmail" />

            <Button
                android:id="@+id/button"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="32dp"
                android:layout_marginTop="24dp"
                android:layout_marginEnd="32dp"
                android:background="@color/colorPrimary"
                android:text="REGISTER"
                android:onClick="@{() -> viewmodel.insertStudent(student)}"
                android:textColor="@android:color/background_light"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/edPassword" />
        </androidx.constraintlayout.widget.ConstraintLayout>


    </androidx.core.widget.NestedScrollView>
</layout>

कमरे में डालने और हटाने के ऑपरेशन को अलग थ्रेड में किया जाना चाहिए, इसे एसिंक्टस्क के साथ पूरा करने के लिए मैंने बहुत संघर्ष किया है। अंत में RxJava में अवलोकनीय एकल प्रकार के साथ ऐसा करने में सक्षम ।

यहाँ rxjava के लिए ग्रेडल निर्भरता है:

implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
implementation 'io.reactivex.rxjava2:rxjava:2.0.3' 

0

@Insert के साथ एन्यूलेट किए गए डॉक्यूमेंट फंक्शन्स के अनुसार rowId वापस कर सकते हैं।

यदि @ इंसर्ट विधि केवल 1 पैरामीटर प्राप्त करती है, तो यह एक लंबा रिटर्न दे सकती है, जो सम्मिलित आइटम के लिए नई पंक्ति है। यदि पैरामीटर एक सरणी या संग्रह है, तो इसके बजाय लंबे समय तक वापस लौटना चाहिए [] या सूची <लंबी>।

इसके साथ मुझे जो समस्या है वह यह है कि यह rowId को लौटाता है और id को नहीं। और मुझे अभी तक पता नहीं चला है कि rowId का उपयोग करके id कैसे प्राप्त करें।

अफसोस की बात है कि मैं अभी तक कोई टिप्पणी नहीं कर सकता, क्योंकि मेरे पास 50 प्रतिष्ठा नहीं है, इसलिए मैं इसे उत्तर के रूप में पोस्ट कर रहा हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.