I have re-read our dialogue and the new FilteredQuery example and decided to use following approach:
1. single table versioning 2. global filtering with temporal options That way i can have whole history in one table and force application to use only "latest" object versions. I agree that in 2018 this approach may look like outdated or legacy for new projects, but it has it's advantages and much simpler as opposed to a event sourcing approach, for example. Thank you so much for helping me! Have a good day, sir! среда, 5 декабря 2018 г., 18:13:11 UTC+3 пользователь Mike Bayer написал: > > On Wed, Dec 5, 2018 at 2:42 AM Stanislav Lobanov <n101...@gmail.com > <javascript:>> wrote: > > > > First of all, thank you for such a detailed answer. Thank you for > sharing your experience and continued support. > > > > Now i understand that using database views is not the best approach. In > the previous project we used an approach with Query objects that were using > WHERE statements to filter needed objects and it worked well. > > > > The problem i want to workaround is that using primary key of (id, > start, end) prevents me from using (lazy loaded) relations out of the box. > > > > Using examples from official sqlalchemy documentation, please think of > Parent and Child as a related business entities: > > > > class Parent(Base): > > __tablename__ = 'parent' > > id = Column(Integer, primary_key=True) > > child_id = Column(Integer, ForeignKey('child.id')) > > child = relationship("Child", back_populates="parents") > > > > class Child(Base): > > __tablename__ = 'child' > > id = Column(Integer, primary_key=True) > > parents = relationship("Parent", back_populates="child") > > > > > > > > There are object relational impedance mismatch: one Parent business > entity can have two Childs. Three business objects. But the database can > have multiple versions of parent or any of children via compound primary > key of (id, start, end) where start and end is a date range. > > OK so just to confirm the first assumption, in your code you only want > to see one Child at a time, that is parent.child is scalar and has > just one date range, right? > > > > > > > My problem is that Children with pk (1, 2018-01-01, 2018-01-02) and (1, > 2018-01-02, 2018-01-03) is in fact one business entity represented as two > model instances in sqlalchemy, so i can non figure out how can i force > relationships between "current" objects to work. > > > > I tried to specify additional conditions on relationships and it worked > for read operations, but failed for write operations. > > With the filtered approach, whether you do it in a view or in the > query, there's just one parent.child object, you just write to it. if > you're talking about the process by which when you write to > parent.child, a new row in the DB replaces it and the row you just saw > goes into "history" , we have a lot of examples of how to do that too > as I had another job for a long time *after* the previous job where we > did everything that way :). Otherwise please be more specific what > "failed for write operations" means. > > > > > > > So i thought i can overcome this situation by using database views and > force sqlalchemy to think that there is only one "current" object at a > time, also for relationships. > > > > Can you give me advice of how to configure sqlalchemy the right way for > this situation? > > > > Is it good idea to use second versioning example, where two tables > created per object (primary and historical table)? > > the tradeoffs with single versioned table vs. table plus historical > have to do with how you want to query the data. when you use a > single table, you have the advantage that you can change the date > range you are injecting into the WHERE clause and you can then load up > a full model in Python that represents a historical snapshot. OTOH > if you just need the "historical" data for an occasional "archive" > view then it may be more convenient to dump changes into a separate > table, and here in Openstack I argue they shouldn't even be doing > that, just dump archive stuff to a file (because we never use our > historical data and it fills up databases with useless crap). in any > case, if you want to really be thorough, you can disable UPDATE > statements on the table in question either through grants or triggers, > since you want to only be doing INSERTs to the table. > > > > > P.S.: sorry for my bad english, it is not on my tongue. > > > > вторник, 4 декабря 2018 г., 15:36:42 UTC+3 пользователь Stanislav > Lobanov написал: > >> > >> Hello. > >> > >> I have a table with schema: > >> > >> name: users > >> fields: id int, name text, start datetime, end datetime > >> primary key: id, start, end > >> > >> This is kind of a historical table, where each row defines separate > "historical version" of an object. There are a single business User entity > (model) with possibly many historical versions. > >> > >> Such table structure makes it very hard to define relationships and > work with related objects. Also it is hard to work with "current" version > of User entity, because to retreive it we need to query it with "now() > between start and end" constraint. > >> > >> So i thought that maybe i can create a view for that table that will > hold only current versions and map that view onto User entity to hide all > historical complexities and compound PK from sqlalchemy. > >> > >> The question: is it possible to implement a mapping that will read from > view but write into real table? > >> > >> For example, view can have fields id (pk) and name. > >> > >> I know that there are great examples of versioning with sqlalchemy but > i want to hide non-functional implementation details from my business > code/entities with view. > >> > >> Thanks! > > > > -- > > SQLAlchemy - > > The Python SQL Toolkit and Object Relational Mapper > > > > http://www.sqlalchemy.org/ > > > > To post example code, please provide an MCVE: Minimal, Complete, and > Verifiable Example. See http://stackoverflow.com/help/mcve for a full > description. > > --- > > You received this message because you are subscribed to the Google > Groups "sqlalchemy" group. > > To unsubscribe from this group and stop receiving emails from it, send > an email to sqlalchemy+...@googlegroups.com <javascript:>. > > To post to this group, send email to sqlal...@googlegroups.com > <javascript:>. > > Visit this group at https://groups.google.com/group/sqlalchemy. > > For more options, visit https://groups.google.com/d/optout. > -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.