Комплексный SQL-запрос с подключением к лифтовой платформе
Я хотел бы знать, есть ли способ выполнить некоторые сложные SQL-запросы, используя Mapper в Liftweb.
На самом деле то, что я хотел бы сделать, - это выполнить запрос Join из баз данных Employes and Departments, используя тот факт, что они связаны отношением "один ко многим".
Другой пример также приветствуется.
Спасибо заранее.
Вот еще несколько деталей: Предположим, у меня есть две таблицы:
Employee : birthday, department ID, salary
Department : department ID, budget, address
Теперь я хотел бы получить список объекта Employee
(созданного с помощью Mapper), который имеет salary > 10$
и a department budget < 100$
.
Конечно, мой исходный код намного сложнее, но моя цель - иметь список отображаемых объектов (т.е. Employee
), соответствующих критериям в собственной таблице или связанной таблице.
Ответы
Ответ 1
Я посмотрел на это. Похоже, что соединения выполняются в объектном слое.
Экстраполируется из http://exploring.liftweb.net/master/index-8.html в ваш случай:
// Accessing foreign objects
class Employee extends LongKeyedMapper[Employee] with IdPK {
...
object department extends MappedLongForeignKey(this, Department)
def departmentName =
Text("My department is " + (department.obj.map(_.name.is) openOr "Unknown"))
}
class Department ... {
...
def entries = Employee.findAll(By(Employee.department, this.id))
}
Если вы хотите делать сопоставления "многие ко многим", вам необходимо предоставить свои собственные
класс "join" с внешними ключами для обоих ваших образованных объектов.
// DepartmentId Entity
class DepartmentId extends LongKeyedMapper[DepartmentId] with IdPK {
def getSingleton = DepartmentId
object name extends MappedString(this,100)
}
object DepartmentId extends DepartmentId with LongKeyedMetaMapper[DepartmentId] {
override def fieldOrder = List(name)
}
Далее мы определяем наш объект соединения, как показано ниже.
Его LongKeyedMapper так же, как и остальные сущности,
но он содержит только поля внешнего ключа для других объектов.
// Join Entity
class DepartmentIdTag extends LongKeyedMapper[DepartmentIdTag] with IdPK {
def getSingleton = DepartmentIdTag
object departmentid extends MappedLongForeignKey(this,DepartmentId)
object Employee extends MappedLongForeignKey(this,Employee)
}
object DepartmentIdTag extends DepartmentIdTag with LongKeyedMetaMapper[DepartmentIdTag] {
def join (departmentid : DepartmentId, tx : Employee) =
this.create.departmentid(departmentid).Employee(tx).save
}
Чтобы использовать объект join, вам нужно создать новый экземпляр и установить
соответствующие внешние ключи, чтобы указать на связанные экземпляры. Как видите,
weve определил метод удобства на нашем метаобъекте Expense, чтобы сделать это.
Чтобы сделать доступным "много-ко многим" как поле на наших объектах, мы можем использовать
HasManyThrough, как показано ниже
// HasManyThrough for Many-to-Many Relationships
class Employee ... {
object departmentids extends HasManyThrough(this, DepartmentId,
DepartmentIdTag, DepartmentIdTag.departmentid, DepartmentIdTag.Employee)
}
Ответ 2
Я заметил, что отдел написан двумя способами: Departement отдел
Возможно, картограф не знает, как перечислить * результаты операции соединения
Вы пробовали следующие
SELECT
e.birthday as birthDay ,
e.departmentId as departmentId ,
e.salary as salary
FROM
Employee e
INNER JOIN Department d
ON e.departmentId = d.departmentId
WHERE
d.budget < 100 AND
e.salary > 10
Отказ от ответственности: у меня есть опыт работы с Mapper/Lift, но у меня есть опыт сопоставления наборов результатов запроса с объектами в Borland С++ Builder, Delphi и Java. Некоторые из этих объектно-ориентированных систем являются ошибками и не могут развернуть SELECT * во все поля, поэтому вам нужно EXPLICITLY рассказать им, какие поля получить.
В вашем случае у вас есть e.departmentId и d.departmentId, которые могут смутить Mapper, не зная, какой из них является истинным. Некоторые системы будут фактически возвращать departmentId и departmentId_1 (по умолчанию он добавляет _1 до конца)
Другие системы просто зависают, выходят из строя, имеют непредсказуемое поведение.
Я также видел существование или отсутствие термина ";" символ в конце будет проблемой в некоторых законченных приложениях SQL.
Ответ 3
Вы всегда можете запускать любой запрос, который вам нравится, с помощью exec или runQuery:
http://scala-tools.org/mvnsites/liftweb-2.4-M1/#net.liftweb.db.DB
Хотя вы также можете делать соединения в Mapper.
Вы можете использовать OneToMany или ManyToMany черты
Чтобы использовать ManyToMany, вы помещаете свои поля соединения. См. Пример кода:
class Meeting extends LongKeyedMapper[Meeting] with IdPK with CreatedUpdated with OneToMany[Long, Meeting] with ManyToMany {
def getSingleton = Meeting
object owner extends MappedLongForeignKey(this, User)
object title extends MappedString(this, 100)
object beginDate extends MappedDateTime(this)
object endDate extends MappedDateTime(this)
object location extends MappedString(this,100)
object description extends MappedText(this)
object allDay extends MappedBoolean(this)
object users extends MappedManyToMany(MeetingUser, MeetingUser.meeting, MeetingUser.user, User)
object contacts extends MappedManyToMany(MeetingContact, MeetingContact.meeting, MeetingContact.contact, Contact)
}
И вот объект объединения.
class MeetingContact extends LongKeyedMapper[MeetingContact] with IdPK with CreatedUpdated {
def getSingleton = MeetingContact
object meeting extends MappedLongForeignKey(this, Meeting)
object contact extends MappedLongForeignKey(this, Contact)
}
object MeetingContact extends MeetingContact with LongKeyedMetaMapper[MeetingContact] {
def join(m: Meeting, c: Contact) = this.create.meeting(m).contact(c).save
def assignedTo(c: Contact) = this.findAll(By(MeetingContact.contact, c)).filter(_.meeting.obj.isDefined).map(_.meeting.obj.open_!)
override def beforeCreate() = MailSender.sendInviteToMeetingContact _ :: super.beforeCreate
}
Ответ 4
Ну, я ничего не знаю о Displayweb mapper, но что касается SQL, это выглядит примерно так:
select e.birthday, e.department_id, e.salary from
employee e left join department d on d.department_id=e.department_id
where d.budget>100 and e.salary>10;
Ответ 5
SQL выглядит следующим образом.
SELECT *
FROM Employee e
INNER JOIN Department d
ON e.departmentId = d.departmentId
WHERE d.budget < 100 AND e.salary > 10