ActiveAndroid Связь «многие ко многим»

В настоящее время я использую ActiveAndroid и последние несколько часов пытаюсь заставить работать отношения «многие ко многим», однако я просто не могу заставить его работать. Я надеюсь, что вы можете мне помочь:

У меня есть модели «Студент» и «Курс», у студента может быть много курсов, а у курса много студентов. В основном это то, что у меня есть в модели «StudentCourse»:

 @Column(name = COURSE)
 public Course course;

 @Column(name = STUDENT)
 public Student student;

 public StudentCourse(Student student, Course course) {
 super();
 this.student = student;
 this.course = course;
 }
//
 public StudentCourse(){ }

 public List<Course> courses(){
 return getMany(Course.class, "StudentCourse");
 }
 public List<Student> students(){
 return getMany(Student.class, "StudentCourse");
 }

Сейчас я пытаюсь получить «всех студентов курса X» с помощью следующего кода:

((Student) new Select().from(StudentCourse.class).where("course = ?",selectedCourse.getId()).executeSingle()).students();

Однако я получаю следующую ошибку:

java.lang.ClassCastException: com.papinotas.models.StudentCourse нельзя преобразовать в com.papinotas.models.Student

Если я изменю состав (Студент) на (Студенческий курс), я получу следующую ошибку:

android.database.sqlite.SQLiteException: такого столбца нет: student.StudentCourse (код 1): , при компиляции: SELECT * FROM student WHERE student.StudentCourse=1

Моя главная цель - надеюсь достичь этого всего за 1 запрос. Любая помощь будет принята с благодарностью. Заранее спасибо!

PS: я уже просмотрел почти все, что смог найти: Active Android many-to - много отношений и https://github.com/pardom/ActiveAndroid/issues/ 46


person Waclock    schedule 05.10.2014    source источник


Ответы (3)


Я бы не стал использовать getMany для этого. Я бы сделал это вместо этого:

return new Select()
    .from(Student.class)
    .innerJoin(StudentCourse.class).on("students.id = studentcourses.id")
    .where("studentcourses.course = ?", courseId)
    .execute();
person Michael Pardo    schedule 05.10.2014

Работайте как шарм:

Класс клиента

 @Table(name = "Client")
 public class Client extends Model{}

Класс контракта

 @Table(name = "Contract")
 public class Contract extends Model{}

Отношения между Клиентом и Контрактом

 @Table(name = "ClientContract")
 public class ClientContract extends Model {

    @Column(name = "Client", onDelete = Column.ForeignKeyAction.CASCADE)
    public Client client;

    @Column(name = "Contract", onDelete = Column.ForeignKeyAction.CASCADE)
    public Contract contract;
}

Помощник базы данных

public class DBHelper {

 public List<Contract> getRelatedContracts(Client client) {
        List<Contract> contracts = null;

        if (client != null && client.isCreated()) {
            contracts = new Select()
                    .from(Contract.class)
                    .innerJoin(ClientContract.class).on("ClientContract.Contract = Contract.id")
                    .where("ClientContract.Client = ?", client.getId())
                    .execute();
        }
        return contracts;
    }

    public List<Client> getRelatedClients(Contract contract) {
        List<Client> clients = null;

        if (contract != null && contract.isCreated()) {
            clients = new Select()
                    .from(Client.class)
                    .innerJoin(ClientContract.class).on("ClientContract.Client = Client.id")
                    .where("ClientContract.Contract = ?", contract.getId())
                    .execute();
        }
        return clients;
    }

    // get relation
    public ClientContract getClientContract(Client client, Contract contract) {
        ClientContract clientContract = null;
        if (client != null && contract != null && client.isCreated() && contract.isCreated()) {

            clientContract = new Select().from(ClientContract.class)
                    .where("Client = ?", client.getId())
                    .where("Contract = ?", contract.getId())
                    .executeSingle();
        }
        return clientContract;
    }

    // add relation
    public ClientContract addClientContract(Client client, Contract contract) {
        ClientContract clientContract = getClientContract(client, contract);

        if (client != null && contract != null && clientContract == null) {

            if (client.getId() == null)
                client.save();

            if (contract.getId() == null)
                contract.save();

            clientContract = new ClientContract();
            clientContract.client = client;
            clientContract.contract = contract;
            clientContract.save();

        }
        return clientContract;
    }

    // delete relation
    public void deleteClientContract(Client client, Contract contract) {
        ClientContract clientContract = getClientContract(client, contract);
        if (clientContract != null && contract.isCreated())
            clientContract.delete();
    }
}
person Oleg Tarashkevich    schedule 29.08.2016

Если я изменю состав (Студент) на (Студенческий курс), я получу следующую ошибку...

На самом деле приведение должно быть (List<StudentCourse>), но настоящая проблема заключается в логике вашей модели здесь. Вы вызываете executeSingle(), но вам действительно нужно несколько объектов StudentCourse, чтобы получить все отношения Student-Course для курса. Ваши методы студентов() и курсов() не имеют особого смысла, так как один объект StudentCourse имеет только одного студента и один курс.

Я бы сделал это так:

List<StudentCourse> enrolments = new Select().from(StudentCourse.class).where("course = ?",selectedCourse.getId()).execute();

List<Student> studentsInCourse = new ArrayList<Student>();
for(StudentCourse enrolment:enrolments)
    studentsInCourse.add(enrolment.student);
person Denley Bihari    schedule 05.10.2014
comment
Я пытался найти способ получить всех студентов с помощью одного запроса; это сделает N запросов, если я не ошибаюсь PS: я понимаю, о чем вы, и я согласен, что это не имеет никакого смысла, я пытался следовать примеру по ссылкам, которые я разместил выше, однако они не работать, как я ожидал, я полагаю. - person Waclock; 06.10.2014
comment
Это единственный запрос SELECT, но затем он выполняет некоторые манипуляции со списком, так что вы получаете список студентов, а не список студенческих курсов. - person Denley Bihari; 06.10.2014
comment
О, enrolment.student не делает запрос к базе данных, тогда вы правы, я думаю! - person Waclock; 06.10.2014
comment
В зависимости от того, для чего вы его используете, вы можете просто оставить его как список объектов StudentCourse (и, возможно, изменить свой класс адаптера или что-то еще, для чего вы его используете). Если вам действительно нужно это как список объектов Student, вы можете выполнить SQL JOIN, чтобы сделать его более эффективным для большого количества студентов. - person Denley Bihari; 06.10.2014