Repository: pydantic/pydantic

Issue:
Mapping sqlalchemy and pydantic's dataclass decorator fails
# Bug

Output of `python -c "import pydantic.utils; print(pydantic.utils.version_info())"`:
```
             pydantic version: 1.8.2
            pydantic compiled: True
                 install path: /home/bay2rng/.local/share/virtualenvs/p356_rtp_production_scheduling-03q6S6S0/lib/python3.9/site-packages/pydantic
               python version: 3.9.5 (default, May  5 2021, 02:58:34)  [GCC 7.5.0]
                     platform: Linux-4.15.0-144-generic-x86_64-with-glibc2.27
     optional deps. installed: ['typing-extensions']

```

We are trying to map sqlalchemy (v. 1.4.17) and pydantic as described [here](https://docs.sqlalchemy.org/en/14/orm/mapping_styles.html#example-two-dataclasses-with-declarative-table) using dataclass decorators.

The code below works fine with `use_pydantic = False` but fails with `use_pydantic = True` with the following message:

```py
sqlalchemy.orm.exc.UnmappedInstanceError: Class '__main__.Table' is mapped, but this instance lacks instrumentation.  This occurs when the instance is created before sqlalchemy.orm.mapper(__main__.Table) was called.
```

Is this a corner case which is not supported by  `pydantic.dataclasses.dataclass` or is this a bug?

```py
use_pydantic = True

from dataclasses import field

from sqlalchemy import Column, String
from sqlalchemy import create_engine
from sqlalchemy.orm import registry, Session

if use_pydantic:
    from pydantic.dataclasses import dataclass
else:
    from dataclasses import dataclass

mapper_registry = registry()
Base = mapper_registry.generate_base()


if __name__ == "__main__":
    engine = create_engine("sqlite:///:memory:")

    @mapper_registry.mapped
    @dataclass
    class Table:
        __tablename__ = "table"

        __sa_dataclass_metadata_key__ = "sa"

        id: str = field(metadata={"sa": Column(String(32), primary_key=True)})

    Base.metadata.create_all(engine)

    with Session(engine) as session:
        session.add(Table(id="123"))

```



Discussion:
I have experienced this issue and discussed it in #1089.

Apologies, I've only discovered this issue now. I think I've found the issue which is more general to pydantic's handling of dataclasses generally. I'll post a new issue in a moment with a working example.

Resolving patch:
diff --git a/pydantic/dataclasses.py b/pydantic/dataclasses.py
--- a/pydantic/dataclasses.py
+++ b/pydantic/dataclasses.py
@@ -98,7 +98,7 @@ def _pydantic_post_init(self: 'Dataclass', *initvars: Any) -> None:
         d, _, validation_error = validate_model(self.__pydantic_model__, input_data, cls=self.__class__)
         if validation_error:
             raise validation_error
-        object.__setattr__(self, '__dict__', d)
+        object.__setattr__(self, '__dict__', {**getattr(self, '__dict__', {}), **d})
         object.__setattr__(self, '__initialised__', True)
         if post_init_post_parse is not None:
             post_init_post_parse(self, *initvars)


Test patch:
diff --git a/tests/test_dataclasses.py b/tests/test_dataclasses.py
--- a/tests/test_dataclasses.py
+++ b/tests/test_dataclasses.py
@@ -920,3 +920,28 @@ class A2:
     assert A2.__pydantic_model__.schema()['properties'] == {
         'a': {'title': 'A', 'description': 'descr', 'type': 'string'}
     }
+
+
+def test_keeps_custom_properties():
+    class StandardClass:
+        """Class which modifies instance creation."""
+
+        a: str
+
+        def __new__(cls, *args, **kwargs):
+            instance = super().__new__(cls)
+
+            instance._special_property = 1
+
+            return instance
+
+    StandardLibDataclass = dataclasses.dataclass(StandardClass)
+    PydanticDataclass = pydantic.dataclasses.dataclass(StandardClass)
+
+    clases_to_test = [StandardLibDataclass, PydanticDataclass]
+
+    test_string = 'string'
+    for cls in clases_to_test:
+        instance = cls(a=test_string)
+        assert instance._special_property == 1
+        assert instance.a == test_string