1

I have encountered a strange problem when using SQLAlchemy and hoping that this community can help.

So the story is as follows:

  1. I have custom classes, where interesting thing is that Forecast class is part of Job class (job should have list of Forecasts inside). They are defined like that:
class Job(db.Model):
    __tablename__ = 'job'
    
    id = db.Column(db.Integer(), primary_key=True)
    job_code = db.Column(db.String(4), nullable=True)
    job_description = db.Column(db.String(200), nullable=False)    
    forecasts = db.relationship('Forecast', order_by="Forecast.time", cascade="all, delete")

class Forecast(db.Model):
    __tablename__ = 'revenue'

    id = db.Column(db.Integer, primary_key=True)
    job_id = db.Column(db.Integer, db.ForeignKey('forecast_job.id'))
    time = db.Column(db.String(7), nullable=False)
    forecast = db.Column(db.Integer, nullable=False)
  1. It works all fine untill this moment. In my code I have option to join 2 jobs together
# Open session to run operation
engine = create_engine(current_app.config["SQLALCHEMY_DATABASE_URI"])
Session = sessionmaker(bind = engine)  
mer_session = Session() 

# Select jobs
old_forecast = mer_session.query(Job).filter(Job.id == manual_id).first()
new_forecast = mer_session.query(Job).filter(Job.id == auto_id).first()

# Copy financial forecast from manual record to automatic one
new_forecast.forecasts = old_forecast.forecasts

# When we do comitt later on it should be all updated

# Delete record manually
mer_session.delete(old_forecast)

#Commit changes
mer_session.commit()
  1. This is critical line: new_forecast.forecasts = old_forecast.forecasts

Where new_forecast.forecasts is empty then it works fine (so I replace no values with new ones). However, when I need to overwrite some old info (new_forecast.forecasts is non empty) then I get the following error:

cursor.executemany(statement, parameters)
sqlalchemy.exc.IntegrityError: (pyodbc.IntegrityError) ('23000', "[23000] [Microsoft][ODBC SQL Server Driver][SQL Server]Cannot insert the value NULL into column 'job_id', table '....dbo.revenue'; column does not allow nulls. UPDATE fails. (515) (SQLExecDirectW); [23000] [Microsoft][ODBC SQL Server Driver][SQL Server]The statement has been terminated. (3621)")

So obviously SQLAlchemy mixes something in Forecast when tryint to add records with emtpy job_id. How to make SQLAlchemy perfor replacement in a way:

  • delete new_forecast.forecasts
  • copy old_forecast.forecasts into new_forecast.forecasts
  • commit changes

I can do it step by step but this is so silly that there must be some automatic way via functinality of SQLAlchemy.

Hikari_PL
  • 21
  • 2
  • "delete-orphan" option is the answer. More details here: https://stackoverflow.com/questions/23323947/sqlalchemy-delete-object-directly-from-one-to-many-relationship-without-using-s – Hikari_PL Oct 24 '21 at 09:42

0 Answers0