- undefinierte Tabelle < /strong> < /li>
Tabellenbeziehung nicht gefunden
Code: Select all
SchemaSwitchMiddleware
from typing import Optional, Callable
from fastapi import Request, Response
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware
from app.db.session import SessionLocal, switch_schema
from app.repositories.tenant_repository import TenantRepository
from app.core.logger import logger
from contextvars import ContextVar
current_schema: ContextVar[str] = ContextVar("current_schema", default="public")
class SchemaSwitchMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: Callable) -> Response:
"""
Middleware to dynamically switch the schema based on the `X-Tenant-ID` header.
If no header is present, defaults to `public` schema.
"""
db = SessionLocal() # Create a session here
try:
tenant_id: Optional[str] = request.headers.get("X-Tenant-ID")
if tenant_id:
try:
tenant_repo = TenantRepository(db)
tenant = tenant_repo.get_tenant_by_id(tenant_id)
if tenant:
schema_name = tenant.schema_name
else:
logger.warning("Invalid Tenant ID received in request headers")
return JSONResponse(
{"detail": "Invalid access"},
status_code=400
)
except Exception as e:
logger.error(f"Error fetching tenant: {e}. Defaulting to public schema.")
db.rollback()
schema_name = "public"
else:
schema_name = "public"
current_schema.set(schema_name)
switch_schema(db, schema_name)
request.state.db = db # Store the session in request state
response = await call_next(request)
return response
except Exception as e:
logger.error(f"SchemaSwitchMiddleware error: {str(e)}")
db.rollback()
return JSONResponse({"detail": "Internal Server Error"}, status_code=500)
finally:
switch_schema(db, "public") # Always revert to public
db.close()
< /code>
Datenbanksitzung (app /db /session.py) < /h2>
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker, declarative_base, Session
from app.core.logger import logger
from app.core.config import settings
# Base for models
Base = declarative_base()
DATABASE_URL = settings.DATABASE_URL
# SQLAlchemy engine
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True,
pool_size=20,
max_overflow=30,
)
# Session factory
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def switch_schema(db: Session, schema_name: str):
"""Helper function to switch the search_path to the desired schema."""
db.execute(text(f"SET search_path TO {schema_name}"))
db.commit()
# logger.debug(f"Switched schema to: {schema_name}")
< /code>
Beispieltabellen < /h2>
öffentliches Schema: Enthält Tabellen wie Benutzer, Rollen, Mieter und User_lookup. < /p>
Mieterschema: Enthält Tabellen wie Benutzer, Rollen, Gebäude und Böden. Bei gleichzeitigen Anfragen kehrt die Umschaltung jedoch manchmal zu früh in das öffentliche Schema zurück, was zu Fehlern führt, da mieterspezifische Tabellen fehlen. >
[*] Was könnte die Rennbedingung verursachen, bei der das Schema der Verbindung bei gleichzeitigen Anfragen in die Öffentlichkeit umgestellt wird? < /li>
Wie kann ich sicherstellen Behält sein Mieterschema im gesamten Anforderungslebenszyklus ohne Störungen durch gleichzeitige Anfragen korrekt ein?
Gibt es einen besseren Ansatz (z. br /> < /ol>
Jede Hilfe auf dieser ist viel apriert. Danke