<p dir="auto"><strong>Describe your question</strong><br>
When i use <code class="notranslate">session.merge</code>, i got a <code class="notranslate">(pymssql.IntegrityError) (2627, b"Violation of PRIMARY KEY constraint 'PK__payment___357D4CF8B9E5C8E5'. Cannot insert duplicate key in object 'dbo.test'</code>. The same in mysql <code class="notranslate">sqlalchemy.exc.IntegrityError: (mysql.connector.errors.IntegrityError) 1062 (23000): Duplicate entry 'payCode_-298' for key 'PRIMARY'</code><br>
<strong>Example (if applicable)</strong></p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base, declared_attr
from sqlalchemy.orm import sessionmaker, scoped_session

from config import Config

engine = create_engine(
    Config.SQLALCHEMY_DATABASE_URI,
    pool_size=Config.SQLALCHEMY_POOL_SIZE,
    max_overflow=Config.SQLALCHEMY_MAX_OVERFLOW,
    pool_recycle=Config.SQLALCHEMY_POOL_RECYCLE,
    # echo=True
)

db_session = scoped_session(
    sessionmaker(autocommit=False, autoflush=False, bind=engine)
)


class Base:
    @declared_attr
    def __tablename__(cls):
        return (
            &quot;&quot;.join(&quot;_%s&quot; % c if c.isupper() else c for c in cls.__name__)
            .strip(&quot;_&quot;)
            .lower()
        )


Base = declarative_base(cls=Base)
class PaymentMethod(Base):
    &quot;&quot;&quot;test&quot;&quot;&quot;

    code = Column(String, primary_key=True, autoincrement=False, comment=&quot;primary_key&quot;)
    name = Column(String, comment=&quot;name&quot;)
    group_id = Column(String, comment=&quot;group_id&quot;)
    shop_id = Column(String, comment=&quot;shop_id&quot;)
    insert_time = Column(DateTime, comment=&quot;insert_time&quot;, default=datetime.now)

data = [{'name': 'payCode_-298', 'value': 'pospalopenpay_yiling.clientscanpos'}, {'name': 'payCode_-299', 'value': 'pospalopenpay_yiling.clientscanpos'}, {&quot;name&quot;:'payCode_-298', 'value': 'pospalopenpay_jlpay.clientscanpos'}, {'name': 'payCode_-299', 'value': 'pospalopenpay_jlpay.clients'}]
for i in data:
    db_session.merge(PaymentMethod(code=i[&quot;name&quot;], name=i['value'], shop_id='test_shop_id', group_id='test_group_id'))
db_session.commit()"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span> <span class="pl-k">import</span> <span class="pl-s1">create_engine</span>
<span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span>.<span class="pl-s1">ext</span>.<span class="pl-s1">declarative</span> <span class="pl-k">import</span> <span class="pl-s1">declarative_base</span>, <span class="pl-s1">declared_attr</span>
<span class="pl-k">from</span> <span class="pl-s1">sqlalchemy</span>.<span class="pl-s1">orm</span> <span class="pl-k">import</span> <span class="pl-s1">sessionmaker</span>, <span class="pl-s1">scoped_session</span>

<span class="pl-k">from</span> <span class="pl-s1">config</span> <span class="pl-k">import</span> <span class="pl-v">Config</span>

<span class="pl-s1">engine</span> <span class="pl-c1">=</span> <span class="pl-en">create_engine</span>(
    <span class="pl-v">Config</span>.<span class="pl-v">SQLALCHEMY_DATABASE_URI</span>,
    <span class="pl-s1">pool_size</span><span class="pl-c1">=</span><span class="pl-v">Config</span>.<span class="pl-v">SQLALCHEMY_POOL_SIZE</span>,
    <span class="pl-s1">max_overflow</span><span class="pl-c1">=</span><span class="pl-v">Config</span>.<span class="pl-v">SQLALCHEMY_MAX_OVERFLOW</span>,
    <span class="pl-s1">pool_recycle</span><span class="pl-c1">=</span><span class="pl-v">Config</span>.<span class="pl-v">SQLALCHEMY_POOL_RECYCLE</span>,
    <span class="pl-c"># echo=True</span>
)

<span class="pl-s1">db_session</span> <span class="pl-c1">=</span> <span class="pl-en">scoped_session</span>(
    <span class="pl-en">sessionmaker</span>(<span class="pl-s1">autocommit</span><span class="pl-c1">=</span><span class="pl-c1">False</span>, <span class="pl-s1">autoflush</span><span class="pl-c1">=</span><span class="pl-c1">False</span>, <span class="pl-s1">bind</span><span class="pl-c1">=</span><span class="pl-s1">engine</span>)
)


<span class="pl-k">class</span> <span class="pl-v">Base</span>:
    <span class="pl-en">@<span class="pl-s1">declared_attr</span></span>
    <span class="pl-k">def</span> <span class="pl-en">__tablename__</span>(<span class="pl-s1">cls</span>):
        <span class="pl-k">return</span> (
            <span class="pl-s">""</span>.<span class="pl-en">join</span>(<span class="pl-s">"_%s"</span> <span class="pl-c1">%</span> <span class="pl-s1">c</span> <span class="pl-k">if</span> <span class="pl-s1">c</span>.<span class="pl-en">isupper</span>() <span class="pl-k">else</span> <span class="pl-s1">c</span> <span class="pl-k">for</span> <span class="pl-s1">c</span> <span class="pl-c1">in</span> <span class="pl-s1">cls</span>.<span class="pl-s1">__name__</span>)
            .<span class="pl-en">strip</span>(<span class="pl-s">"_"</span>)
            .<span class="pl-en">lower</span>()
        )


<span class="pl-v">Base</span> <span class="pl-c1">=</span> <span class="pl-en">declarative_base</span>(<span class="pl-s1">cls</span><span class="pl-c1">=</span><span class="pl-v">Base</span>)
<span class="pl-k">class</span> <span class="pl-v">PaymentMethod</span>(<span class="pl-v">Base</span>):
    <span class="pl-s">"""test"""</span>

    <span class="pl-s1">code</span> <span class="pl-c1">=</span> <span class="pl-v">Column</span>(<span class="pl-v">String</span>, <span class="pl-s1">primary_key</span><span class="pl-c1">=</span><span class="pl-c1">True</span>, <span class="pl-s1">autoincrement</span><span class="pl-c1">=</span><span class="pl-c1">False</span>, <span class="pl-s1">comment</span><span class="pl-c1">=</span><span class="pl-s">"primary_key"</span>)
    <span class="pl-s1">name</span> <span class="pl-c1">=</span> <span class="pl-v">Column</span>(<span class="pl-v">String</span>, <span class="pl-s1">comment</span><span class="pl-c1">=</span><span class="pl-s">"name"</span>)
    <span class="pl-s1">group_id</span> <span class="pl-c1">=</span> <span class="pl-v">Column</span>(<span class="pl-v">String</span>, <span class="pl-s1">comment</span><span class="pl-c1">=</span><span class="pl-s">"group_id"</span>)
    <span class="pl-s1">shop_id</span> <span class="pl-c1">=</span> <span class="pl-v">Column</span>(<span class="pl-v">String</span>, <span class="pl-s1">comment</span><span class="pl-c1">=</span><span class="pl-s">"shop_id"</span>)
    <span class="pl-s1">insert_time</span> <span class="pl-c1">=</span> <span class="pl-v">Column</span>(<span class="pl-v">DateTime</span>, <span class="pl-s1">comment</span><span class="pl-c1">=</span><span class="pl-s">"insert_time"</span>, <span class="pl-s1">default</span><span class="pl-c1">=</span><span class="pl-s1">datetime</span>.<span class="pl-s1">now</span>)

<span class="pl-s1">data</span> <span class="pl-c1">=</span> [{<span class="pl-s">'name'</span>: <span class="pl-s">'payCode_-298'</span>, <span class="pl-s">'value'</span>: <span class="pl-s">'pospalopenpay_yiling.clientscanpos'</span>}, {<span class="pl-s">'name'</span>: <span class="pl-s">'payCode_-299'</span>, <span class="pl-s">'value'</span>: <span class="pl-s">'pospalopenpay_yiling.clientscanpos'</span>}, {<span class="pl-s">"name"</span>:<span class="pl-s">'payCode_-298'</span>, <span class="pl-s">'value'</span>: <span class="pl-s">'pospalopenpay_jlpay.clientscanpos'</span>}, {<span class="pl-s">'name'</span>: <span class="pl-s">'payCode_-299'</span>, <span class="pl-s">'value'</span>: <span class="pl-s">'pospalopenpay_jlpay.clients'</span>}]
<span class="pl-k">for</span> <span class="pl-s1">i</span> <span class="pl-c1">in</span> <span class="pl-s1">data</span>:
    <span class="pl-s1">db_session</span>.<span class="pl-en">merge</span>(<span class="pl-v">PaymentMethod</span>(<span class="pl-s1">code</span><span class="pl-c1">=</span><span class="pl-s1">i</span>[<span class="pl-s">"name"</span>], <span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s1">i</span>[<span class="pl-s">'value'</span>], <span class="pl-s1">shop_id</span><span class="pl-c1">=</span><span class="pl-s">'test_shop_id'</span>, <span class="pl-s1">group_id</span><span class="pl-c1">=</span><span class="pl-s">'test_group_id'</span>))
<span class="pl-s1">db_session</span>.<span class="pl-en">commit</span>()</pre></div>
<p dir="auto"><strong>Additional context</strong><br>
Add any other context or screenshots about the feature request here.<br>
The tables in the database are clean</p>
<p dir="auto"><strong>Have a nice day!</strong></p>
<p dir="auto"><strong>Migrated issue, originally created by Anonymous</strong></p>
<p dir="auto">(original reporter: ged) Is this intended? It used to work in 0.5.xxx...</p>
<hr>
<p dir="auto">Attachments: <a href="../wiki/imported_issue_attachments/1765/test_fk.py">test_fk.py</a> | <a href="../wiki/imported_issue_attachments/1765/1765.patch">1765.patch</a></p>