অ্যান্ড্রয়েড রুম: রুম ব্যবহার করে সম্পর্কের সত্তা .োকান


90

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

পোস্টটি কীভাবে ডাটাবেস থেকে মানগুলি পড়তে পারে তা সত্ত্বেও ডাটাবেসগুলিতে সত্তাগুলি সংরক্ষণ করার ফলে userIdখালি হয়ে যায় যার অর্থ 2 টেবিলের মধ্যে কোনও সম্পর্ক নেই।

আমি নিশ্চিত নই যে মান থাকার সময় insertএকটি Userএবং List of Petডাটাবেসে প্রবেশের আদর্শ উপায় কী userId

1) ব্যবহারকারী সত্ত্বা:

@Entity
public class User {
    @PrimaryKey
    public int id; // User id
}

2) পোষা সত্তা:

@Entity
public class Pet {
    @PrimaryKey
    public int id;     // Pet id
    public int userId; // User id
    public String name;
}

3) ব্যবহারকারীর উইথপেটস ​​পোজো:

// Note: No annotation required at this class definition.
public class UserWithPets {
   @Embedded
   public User user;

   @Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class)
   public List<Pet> pets;
}

এখন ডিবি থেকে রেকর্ডগুলি আনতে আমরা নিম্নলিখিতটি ব্যবহার করি DAO:

@Dao
public interface UserDao {
    @Insert
    fun insertUser(user: User)

    @Query("SELECT * FROM User")
    public List<UserWithPets> loadUsersWithPets();
}

সম্পাদনা

আমি ইস্যু ট্র্যাকারটিতে এই সমস্যাটি https://issuetracker.google.com/issues/62848977 তৈরি করেছি । আশা করি তারা এ বিষয়ে কিছু করবেন।


সুতরাং তারা বলছেন "সম্পর্ক" 2.2 আপডেটে অগ্রাধিকার। বর্তমান সংস্করণ 4 ডিসেম্বর 2018 থেকে "রুম 2.1.0-alpha03" হয়
লেচ Osiński

হ্যাঁ, ইস্যু ট্র্যাকারে তাদের মন্তব্যটি পড়ুন। এটি সময় নিতে পারে, ইতিমধ্যে আপনি কাজের
ক্ষেত্রগুলি

উত্তর:


44

আপনি আপনার দাওটিকে একটি ইন্টারফেস থেকে একটি বিমূর্ত শ্রেণিতে পরিবর্তন করে এটি করতে পারেন।

@Dao
public abstract class UserDao {

    public void insertPetsForUser(User user, List<Pet> pets){

        for(Pet pet : pets){
            pet.setUserId(user.getId());
        }

        _insertAll(pets);
    }

    @Insert
    abstract void _insertAll(List<Pet> pets);  //this could go in a PetDao instead...

    @Insert
    public abstract void insertUser(User user);

    @Query("SELECT * FROM User")
    abstract List<UserWithPets> loadUsersWithPets();
}

আপনি একটি Userঅবজেক্ট থাকায় আরও এগিয়ে যেতে পারেন@Ignored List<Pet> pets

@Entity
public class User {
    @PrimaryKey
    public int id; // User id

    @Ignored
    public List<Pet> pets
}

এবং তারপরে দাও UserWithPetsব্যবহারকারীর কাছে মানচিত্র তৈরি করতে পারে:

public List<User> getUsers() {
    List<UserWithPets> usersWithPets = loadUserWithPets();
    List<User> users = new ArrayList<User>(usersWithPets.size())
    for(UserWithPets userWithPets: usersWithPets) {
        userWithPets.user.pets = userWithPets.pets;
        users.add(userWithPets.user);
    }
    return users;
}

এটি আপনাকে পুরো দাওয়ের সাথে ছেড়ে দেয়:

@Dao
public abstract class UserDao {

    public void insertAll(List<User> users) {
        for(User user:users) {
           if(user.pets != null) {
               insertPetsForUser(user, user.pets);
           }
        }
        _insertAll(users);
    }

    private void insertPetsForUser(User user, List<Pet> pets){

        for(Pet pet : pets){
            pet.setUserId(user.getId());
        }

        _insertAll(pets);
    }

    public List<User> getUsersWithPetsEagerlyLoaded() {
        List<UserWithPets> usersWithPets = _loadUsersWithPets();
        List<User> users = new ArrayList<User>(usersWithPets.size())
        for(UserWithPets userWithPets: usersWithPets) {
            userWithPets.user.pets = userWithPets.pets;
            users.add(userWithPets.user);
        }
        return users;
    }


    //package private methods so that wrapper methods are used, Room allows for this, but not private methods, hence the underscores to put people off using them :)
    @Insert
    abstract void _insertAll(List<Pet> pets);

    @Insert
    abstract void _insertAll(List<User> users);

    @Query("SELECT * FROM User")
    abstract List<UserWithPets> _loadUsersWithPets();
}

পরিবর্তে কোনও পেটডাওতে আপনি পদ্ধতিগুলি insertAll(List<Pet>)এবং insertPetsForUser(User, List<Pet>)পদ্ধতিগুলি রাখতে চাইতে পারেন ... কীভাবে আপনি আপনার ডিএওগুলি বিভক্ত করবেন! :)

যাইহোক, এটি ঠিক অন্য একটি বিকল্প। ডেটাসোর্স অবজেক্টগুলিতে আপনার ডিএওগুলি মোড়ানোও কাজ করে।


সুবিধার পদ্ধতিটি ইন্টারফেসের পরিবর্তে অ্যাবস্ট্র্যাক্ট ক্লাসে রাখার দুর্দান্ত ধারণা।
অক্ষয় Chordiya

7
যদি আমরা পোষা প্রাণী সম্পর্কিত পদ্ধতিগুলি পেটডাওতে স্থানান্তরিত করি, তবে আমরা কীভাবে ইউজারডাওয়ের মধ্যে পেটডাও পদ্ধতিগুলি উল্লেখ করব?
31:18

4
আপনার উত্তরের জন্য ধন্যবাদ. তবে কীভাবে insertPetsForUser (ব্যবহারকারীর ব্যবহারকারী, তালিকা <পেট> পোষা প্রাণী) পদ্ধতিতে pet.setUserId (user.getId ()) ব্যবহারকারী ID সেট করে? আসুন ধরে নিই যে আপনি কোনও এআইপিআই থেকে ব্যবহারকারীর অবজেক্ট পাচ্ছেন এবং এই মুহুর্তে এটির কোনও আইডি নেই (প্রাইমারিকি) যেহেতু এটি রুমডবিতে সংরক্ষণ করা হয়নি, সুতরাং ইউজারআরটায়ড () কল করা প্রতিটিটির জন্য কেবল 0 এর একটি ডিফল্ট মান অর্জন করবে এটি সংরক্ষণ করা এখনও হিসাবে ব্যবহারকারী। আপনি কীভাবে এটি পরিচালনা করবেন কারণ ইউজার.জেটআইডি () সর্বদা প্রতিটি ব্যবহারকারীর জন্য 0 প্রদান করে। ধন্যবাদ
ইখিলোয়া ইমোখাই

40

রুম লাইব্রেরিতে কোনও আপডেট না হওয়া পর্যন্ত কোনও নেটিভ সমাধান নেই তবে আপনি কৌতূহল দ্বারা এটি করতে পারেন। নীচে উল্লিখিত সন্ধান করুন।

  1. কেবল পোষা প্রাণী সহ একটি ব্যবহারকারী তৈরি করুন (পোষা প্রাণীকে উপেক্ষা করুন)। গেটর এবং সেটার যুক্ত করুন। লক্ষ্য করুন যে আমাদের আইডির পরে ম্যানুয়ালি সেট করতে হবে এবং ব্যবহার করতে পারছি না autogenerate

    @Entity
    public class User {
          @PrimaryKey
          public int id; 
    
          @Ignore
          private List<Pet> petList;
    }
    
  2. একটি পোষা প্রাণী তৈরি করুন।

    @Entity 
    public class Pet 
    {
        @PrimaryKey
        public int id;     
        public int userId; 
        public String name;
    }
    
  3. ইউজারডাও একটি ইন্টারফেসের পরিবর্তে একটি বিমূর্ত শ্রেণি হওয়া উচিত। তারপরে অবশেষে আপনার ইউজারডাওতে।

    @Insert
    public abstract void insertUser(User user);
    
    @Insert
    public abstract void insertPetList(List<Pet> pets);
    
    @Query("SELECT * FROM User WHERE id =:id")
    public abstract User getUser(int id);
    
    @Query("SELECT * FROM Pet WHERE userId =:userId")
    public abstract List<Pet> getPetList(int userId);
    
    public void insertUserWithPet(User user) {
        List<Pet> pets = user.getPetList();
        for (int i = 0; i < pets.size(); i++) {
            pets.get(i).setUserId(user.getId());
        }
        insertPetList(pets);
        insertUser(user);
    }
    
    public User getUserWithPets(int id) {
        User user = getUser(id);
        List<Pet> pets = getPetList(id);
        user.setPetList(pets);
        return user;
    }
    

ইউজার উইথপেটস ​​পজো তৈরি না করেই আপনার সমস্যার সমাধান করা যেতে পারে।


4
আমি এটি পছন্দ করি কারণ এটি ইউজার উইথপেটস ​​পোজো এড়িয়ে চলে। ডিফল্ট পদ্ধতি ব্যবহার করে ডিএও ইন্টারফেসও হতে পারে। কেবলমাত্র খারাপ দিক আমি দেখতে পাচ্ছি যে insertUser () এবং insertPetList () সর্বজনীন পদ্ধতি, তবে এটি ক্লায়েন্ট দ্বারা ব্যবহার করা উচিত নয়। উপরে উল্লিখিত হিসাবে, এগুলি ব্যবহার করা উচিত নয় তা দেখানোর জন্য আমি এই পদ্ধতিগুলির নামের আগে একটি আন্ডারস্কোর রেখেছি।
guglhupf

4
কেউ কীভাবে কোনও কার্যকলাপে এটি সঠিকভাবে প্রয়োগ করতে পারেন? ঠিক জানি আমি কীভাবে সঠিকভাবে আইডি তৈরি করতে হয় তা জানি না।
ফিলিপ

@ ফিলিপিস আমি এইডস তৈরির পদ্ধতি নিয়ে কাজ করছি, আপনি কি কোনও সমাধান খুঁজে পেয়েছেন?
sochas

4
আপনার জবাবের জন্য ধন্যবাদ ফিলিপ, আমি এটি একইভাবে করেছি :)
সোহাগাস

4
ধন্যবাদ @ ফিলিপ আমি আপনার উত্তরটি এর নমনীয়তার জন্য পছন্দ করি! আইডি তৈরির জন্য, আমার ক্ষেত্রে আমি insertUser()প্রথমে স্বয়ংক্রিয়-উত্পন্ন হওয়ার জন্য কল করি userId, তারপরে এটি userIdপোষ্য শ্রেণিতে ইউজারআইডি ফিল্ডে নির্ধারণ করুন , তারপরে লুপ করুন insertPet()
রবার্ট

11

ঘর যেমন সত্তাগুলির সম্পর্ক পরিচালনা করে না, আপনাকে userIdনিজের প্রতিটি পোষ্যকে নিজেরাই সেট করতে হবে এবং সেগুলি সংরক্ষণ করতে হবে। যতক্ষণ না একসাথে খুব বেশি পোষা প্রাণী নেই, আমি insertAllএটিকে ছোট রাখার জন্য একটি পদ্ধতি ব্যবহার করব ।

@Dao
public interface PetDao {
    @Insert
    void insertAll(List<Pet> pets);
}

আমি এই মুহুর্তে আর কোন ভাল উপায় আছে বলে মনে করি না।

হ্যান্ডলিংটিকে আরও সহজ করার জন্য, আমি ডিএওগুলির উপরে স্তরটিতে একটি বিমূর্ততা ব্যবহার করব:

public void insertPetsForUser(User user, List<Pet> pets){

    for(Pet pet : pets){
        pet.setUserId(user.getId());
    }

    petDao.insertAll(pets);
}

আমি একই ব্যবহার করে চেষ্টা করেছি Stream। আমি আশা করি এটি করার আরও ভাল উপায় আছে।
অক্ষয় চর্দিয়া

আমি মনে করি না এর চেয়ে আরও ভাল উপায় আছে, কারণ ডকুমেন্টেশনে বলা হয়েছে যে তারা ইচ্ছাকৃতভাবে গ্রন্থাগারটির বাইরে রেফারেন্স রেখেছিল: developer.android.com/topic/libraries/architecture/…
tknell

আমি ইস্যু ট্র্যাকারে এই ইস্যুটি ইস্যুটিউটরেকার.কম . / issues/62848977 তৈরি করেছি । আশা করি তারা এ বিষয়ে কিছু করবেন।
অক্ষয় চর্দিয়া

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

6

বর্তমানে এই সমস্যার কোনও নেটিভ সমাধান নেই । আমি গুগলের ইস্যু ট্র্যাকারে এই https://issuetracker.google.com/issues/62848977 তৈরি করেছি এবং আর্কিটেকচার উপাদান দলটি জানিয়েছে তারা রুম লাইব্রেরির v1.0 এর বা তার পরে একটি নেটিভ সমাধান যুক্ত করবে will

অস্থায়ী কর্মক্ষেত্র:

ইতিমধ্যে আপনি tknell দ্বারা উল্লিখিত সমাধানটি ব্যবহার করতে পারেন ।

public void insertPetsForUser(User user, List<Pet> pets){

    for(Pet pet : pets){
        pet.setUserId(user.getId());
    }

    petDao.insertAll(pets);
}

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

5

এখন v2.1.0 এ ঘরটি নেস্টেড সম্পর্কযুক্ত মডেলগুলির জন্য উপযুক্ত নয় বলে মনে হচ্ছে। এগুলি বজায় রাখতে এটির প্রচুর বয়লারপ্লিট কোড দরকার। যেমন তালিকার ম্যানুয়াল সন্নিবেশ, স্থানীয় আইডি তৈরি এবং ম্যাপিং।

এই সম্পর্ক-ম্যাপিং ক্রিয়াকলাপগুলি বক্সের বাইরে https://github.com/requery/requery সংযোজন দ্বারা সম্পন্ন হয় এটিতে এনামগুলি সন্নিবেশ করাতে সমস্যা নেই এবং ইউআরআই-এর মতো অন্যান্য জটিল ধরণের জন্য কিছু কনভার্টার রয়েছে।


2

আমি এটি তুলনামূলক সহজ ওয়ার্কআরউন্ড দিয়ে সঠিকভাবে সন্নিবেশ করানোতে সক্ষম হয়েছি। এখানে আমার সত্তা:

   @Entity
public class Recipe {
    @PrimaryKey(autoGenerate = true)
    public long id;
    public String name;
    public String description;
    public String imageUrl;
    public int addedOn;
   }


  @Entity
public class Ingredient {
   @PrimaryKey(autoGenerate = true)
   public long id;
   public long recipeId; 
   public String name;
   public String quantity;
  }

public class RecipeWithIngredients {
   @Embedded
   public  Recipe recipe;
   @Relation(parentColumn = "id",entityColumn = "recipeId",entity = Ingredient.class)
   public List<Ingredient> ingredients;

আমি স্বতঃবৃদ্ধি মূল্যের জন্য অটোজেনারেট ব্যবহার করছি (দীর্ঘকাল একটি পোরপোস সহ ব্যবহৃত হয়)। এখানে আমার সমাধান:

  @Dao
public abstract class RecipeDao {

  public  void insert(RecipeWithIngredients recipeWithIngredients){
    long id=insertRecipe(recipeWithIngredients.getRecipe());
    recipeWithIngredients.getIngredients().forEach(i->i.setRecipeId(id));
    insertAll(recipeWithIngredients.getIngredients());
  }

public void delete(RecipeWithIngredients recipeWithIngredients){
    delete(recipeWithIngredients.getRecipe(),recipeWithIngredients.getIngredients());
  }

 @Insert
 abstract  void insertAll(List<Ingredient> ingredients);
 @Insert
 abstract long insertRecipe(Recipe recipe); //return type is the key here.

 @Transaction
 @Delete
 abstract void delete(Recipe recipe,List<Ingredient> ingredients);

 @Transaction
 @Query("SELECT * FROM Recipe")
 public abstract List<RecipeWithIngredients> loadAll();
 }

সত্তাগুলি সংযোগ স্থাপন করতে আমার সমস্যা ছিল, অটো তৈরি করে "রেসিপিআইডি = 0" সারাক্ষণ উত্পন্ন হয়। রেসিপি সত্তা সন্নিবেশ করানো প্রথমে এটি আমার জন্য স্থির করে।

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