SQLAlchemy один ко многим без дочерней таблицы, имеющей первичный ключ

Можно ли создать таблицу без первичного ключа в SQLAlchemy? Отношение, которое я хочу определить, выглядит следующим образом:

class TPost(Base):
  __tablename__ = "forum_post"
  id = Column(Integer, primary_key = True)
  topic_id = Column(Integer, ForeignKey("forum_topic.id"))
  index = Column(Integer)
  page = Column(Integer)
  user_id = Column(Integer, ForeignKey("forum_user.id"))
  posted_at = Column(DateTime)
  post_text = Column(String)
  has_quotes = Column(Boolean)
  quotes = relationship("TQuote")

class TQuote(Base):
  __tablename__ = "forum_quotes"
  id = Column(Integer, ForeignKey("forum_post.id"))
  is_direct = Column(Boolean)
  quoted_text = Column(String)
  quoted_id = Column(Integer)   

Как видите, мне не нужен первичный ключ, и я не собираюсь расширять отношения Quote в будущем.

Моя проблема конкретно представлена ​​этим сообщением об ошибке:

sqlalchemy.exc.ArgumentError: Mapper Mapper|TQuote|forum_quotes 
could not assemble any primary key columns for mapped table 'forum_quotes'

редактировать: пара (id,quoted_id) уникальна и присутствует в большинстве данных, однако, когда цитата не является прямой (и в этом случае не имеет цитируемого_id), я встраиваю цитируемый текст непосредственно в отношении цитаты. Я мог бы использовать подход с двумя таблицами (где непрямые кавычки имеют таблицу с первичным ключом), но я бы предпочел реализовать это как единую связь «один ко многим». Я не хочу делать больше, чем одно соединение.

изменить 2:

Я пронумерую кавычки и использую сгенерированный внешний ключ + номер приложения в качестве pkey, но это все еще раздражает. Теперь разберусь с синтаксисом.

изменить 3:

Решил проблему, как указано в редактировании 2. Сильно раздражает алхимия sql, поскольку у нее есть вся информация, необходимая для реализации взаимосвязи, даже при моделировании данных на высоком уровне. Я понимаю причины, по которым Sql Alchemy хочет иметь первичный ключ (облегчает реализацию формы).

Я начинаю задаваться вопросом, почему я использую Sql Alchemy, без нее я мог бы реализовать односторонние асинхронные операции UPSERT или CREATE_IF_NOT_EXIST с использованием psycopg2. ORM действительно нужно наверстать упущенное.


person Hassan Syed    schedule 27.06.2012    source источник
comment
почему вы пытаетесь сопротивляться использованию одного из них? это размер? чистота модели данных? другая причина?   -  person van    schedule 28.06.2012
comment
Чистота в первую очередь. Но если подумать, увеличение Seeializer — это еще одна операция с базой данных.   -  person Hassan Syed    schedule 28.06.2012
comment
Да, но даже если вы не определите PK, база данных все равно сохранит его внутри и выполнит ту же операцию увеличения. Использование PK действительно хорошо оптимизировано для всех СУБД. Google для суррогатных первичных ключей, и вы можете прийти к выводу, что наличие PK (даже если он вам не нужен) на самом деле является самым простым для моделирования RDB. Но самое главное, вы ничего не сэкономите, не имея его. По соображениям производительности вы можете определить индекс CLUSTED для столбцов (id, quoted_id) вместо столбца PK, если вы в основном выполняете поиск по (id, quoted_id).   -  person van    schedule 28.06.2012
comment
Проблема в том, что пара id-id в кавычках доступна только для сообщений на форуме, которые цитируются с помощью кнопки ответа на это сообщение, вы также можете поместить несвязанные кавычки. Для них цитируемый идентификатор недоступен. Поэтому мой единственный выбор - использовать сериализованный (автоинкрементный) идентификатор или разделить типы цитат на две таблицы.   -  person Hassan Syed    schedule 28.06.2012
comment
Я предполагаю, что эти комментарии подразумевают, что алхимия sql не может работать с таблицами без первичных ключей? Это позор, потому что моей последней задачей был многомиллионный набор данных, состоящий из 10 гигабайт загруженных данных. каждый байт имеет значение в таких ситуациях.   -  person Hassan Syed    schedule 28.06.2012
comment
Как упоминалось ранее (хотя я не уверен в этом на 100%, поэтому вам следует спросить администраторов SQL), даже если вы не создаете PK, в любом случае будет создан какой-то внутренний идентификатор, который все равно будет занимать место. Также вы упомянули, что чистота является основным условием, а теперь это размер. Мне интересно, не пытаетесь ли вы втиснуть оптимизацию в неправильное место. Но, пожалуйста, опубликуйте результаты вашего исследования и решения. Спасибо.   -  person van    schedule 28.06.2012
comment
Я очень подозрительно отношусь к идее, что таблица может быть полезна без первичного ключа. Первичные ключи — это то, как вы определяете какую строку, что очень похоже на понятие идентификатора объекта в ООП. Тот факт, что sqlalchemy навязывает это мировоззрение, ИМНШО, хорошо. Не путаете ли вы идею первичного ключа (который может, например, включать все строки в таблице) с суррогатным ключом (который не является атрибутом реального мира, обычно это небольшое целое число, сгенерированное примитивом базы данных)?   -  person SingleNegationElimination    schedule 29.06.2012
comment
4 байта — это не мало, когда у вас несколько миллионов записей, в данном случае — нет. Я не люблю платить за то, что мне не нужно.   -  person Hassan Syed    schedule 29.06.2012
comment
Еще один способ выразить точку зрения TokenMacGuy: это даже не таблица в реляционной базе данных, если у нее нет первичного ключа. В этом случае это будет что-то вроде электронной таблицы. Но даже не это, потому что у электронной таблицы есть первичный ключ: номер строки. Существует простой вопрос, на который можно ответить «да» или «нет», который отличает это: Разрешите ли вы строки в таблице, которые являются точными дубликатами друг друга? Если вы этого не сделаете, вам нужен НЕКОТОРЫЙ первичный ключ. Более того, если бы вы разрешили разрешить нескольким строкам быть точными копиями друг друга, что бы это вообще значило для вашего приложения?   -  person cdaddr    schedule 30.06.2012
comment
Я верю в реляционную теорию, я получил первое место в каждой реляционной теории данных / баз данных на каждом курсе, который я проходил. Однако природа данных требует, насколько точно следует соблюдать относительную чистоту. Когда вы можете предсказать природу данных и то, как вы будете запрашивать их, вы имеете полное право игнорировать элементы реляционной теории. В этом случае вероятность дублирования ОЧЕНЬ мала, а дубликаты не имеют значения. Каждая БД, которую я знаю (mysql, postgres, sql server), делает таблицы без ключей pkey, и для этого, очевидно, есть причина.   -  person Hassan Syed    schedule 02.07.2012
comment
Кроме того, выбранный мной вариант неявно сортирует данные более эффективно, чем если бы я дал им традиционный последовательный первичный ключ.   -  person Hassan Syed    schedule 02.07.2012


Ответы (2)


Я предполагаю, что @TokenMacGuy прав, и вы действительно путаете понятия PrimaryKey и surrogate key. В таком случае ответ на ваш вопрос:

  • НЕТ, SA не поддерживает таблицы (и, следовательно, отношения к таблицам) без первичного ключа
  • и НЕТ, вам не нужно создавать суррогатный ключ для каждой таблицы в целях использования в качестве primary key. Вы можете определить PK, используя любую комбинацию уникальных столбцов.

См. код ниже для примера:

class TPost(Base):
    __tablename__ = 'forum_post'
    id = Column(Integer, primary_key = True)
    post_text = Column(String)
    quotes = relationship("TQuote", backref="post")

class TQuote(Base):
    __tablename__ = "forum_quotes"
    id = Column(Integer, ForeignKey("forum_post.id"))
    is_direct = Column(Boolean)
    quoted_text = Column(String)
    quoted_id = Column(Integer) 
    __table_args__ = (PrimaryKeyConstraint(id, quoted_id),)
person van    schedule 29.06.2012
comment
Спасибо за ответ, и я +1. (id,quoted_id) = кандидат тогда и только тогда, когда id_direct = true (в эту категорию попадает 75% данных). Итак, чтобы иметь ключ-кандидат для всех данных, я использую новое поле + id новое поле — это увеличенное число, сгенерированное приложением. Так что обновите свой пост, и я приму ‹3 - person Hassan Syed; 02.07.2012
comment
Я думаю, что ответил на вопрос так, как он был задан, и не вижу, как я могу его улучшить. Вы можете принять это (или нет) с дополнительным комментарием (который вы разместили) о том, как вы решили проблему. Или вы можете добавить свое собственное решение и принять его для полноты. - person van; 03.07.2012

Добавьте дополнительный столбец, чтобы дать кавычкам индекс, а затем добавьте составной ключ этого нового столбца + внешний ключ.

person Hassan Syed    schedule 03.07.2012