MS Dynamics Web API 특이점: 다형성 필드의 이상한 사례
I’m happy to translate the article for you, but I need the full text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line and all formatting exactly as you requested.
Microsoft Dynamics 365 / Dataverse와 통합해 본 적이 있다면, 거의 즉시 이상한 점을 눈치챘을 것입니다.
레코드를 조회하면 다음과 같은 필드를 보게 됩니다:
{
"_ownerid_value": "151F639c-1c73-eb11-b1ab-000d3a253b40"
}
하지만 레코드를 생성하거나 업데이트할 때, API는 갑자기 다음과 같은 형태를 기대합니다:
{
"ownerid@odata.bind": "/systemusers(151F639c-1c73-eb11-b1ab-000d3a253b40)"
}
그리고 필드가 다형성(polymorphic)인 경우, 속성 이름이 다시 바뀌기도 합니다:
{
"parentcustomerid_account@odata.bind": "/accounts(ce9eaaef-f718-ed11-b83e-00224837179f)"
}
Dynamics Web API에서 가장 혼란스러운 부분 중 하나인 lookup 및 다형성 필드에 오신 것을 환영합니다. 어떤 일이 일어나고 있는지 살펴보겠습니다.
Dynamics에서 다형성 필드란 무엇인가?
Dynamics의 일부 관계는 여러 엔터티 유형을 가리킬 수 있습니다.
Example metadata:
{
"LogicalName": "ownerid",
"Targets": [
"systemuser",
"team"
]
}
이는 레코드 소유자가 다음과 같을 수 있음을 의미합니다:
- 시스템 사용자
- 팀
다형성 조회의 다른 예는 다음과 같습니다:
| 필드 | 가능한 대상 |
|---|---|
ownerid | systemuser, team |
customerid | account, contact |
regardingobjectid | 다수의 엔터티 |
개념적으로 이것은 강력합니다: 스키마가 하나의 관계 필드가 여러 테이블을 가리키도록 허용합니다. 하지만 이는 몇 가지 흥미로운 API 동작을 초래합니다.
동일한 필드에 대한 3가지 다른 이름
1️⃣ 메타데이터 이름
스키마 또는 메타데이터에서: ownerid
2️⃣ 레코드 조회
레코드를 가져올 때 필드는 __value 로 변환됩니다.
예시 응답:
{
"_ownerid_value": "151F639c-1c73-eb11-b1ab-000d3a253b40"
}
추가 주석이 자주 나타납니다:
{
"_ownerid_value": "GUID",
"_ownerid_value@Microsoft.Dynamics.CRM.lookuplogicalname": "systemuser",
"_ownerid_value@OData.Community.Display.V1.FormattedValue": "John Smith"
}
의미:
| 속성 | 의미 |
|---|---|
_ownerid_value | GUID |
lookuplogicalname (주석) | 엔터티 유형 |
FormattedValue (주석) | 표시값 |
따라서 데이터를 읽을 때 관계를 이해하려면 세 가지 별도 정보를 해석해야 합니다.
3️⃣ 레코드 작성
레코드를 생성하거나 업데이트할 때 Dynamics는 OData 바인딩을 기대합니다: @odata.bind.
예시:
{
"ownerid@odata.bind": "/systemusers(151F639c-1c73-eb11-b1ab-000d3a253b40)"
}
패턴:
@odata.bind : "/<entityset>(GUID)"
(엔터티 세트 이름은 복수형이어야 합니다.)
다형성 필드가 더욱 이상해질 때
일부 다형성 조회에서는 엔터티 이름을 속성에 포함시켜야 합니다.
예시
{
"parentcustomerid_account@odata.bind": "/accounts(GUID)"
}
{
"parentcustomerid_contact@odata.bind": "/contacts(GUID)"
}
패턴:
<field>_<entity>_@odata.bind
대상 엔터티에 따라 속성 이름 자체가 변경되므로 특히 혼란스러울 수 있습니다.
특수 경우: ownerid
ownerid는 약간 다르게 동작합니다. 다른 다형 필드와 달리 엔터티 접미사를 포함하지 않습니다. 다음 두 가지 모두 작동합니다:
{
"ownerid@odata.bind": "/systemusers(GUID)"
}
{
"ownerid@odata.bind": "/teams(GUID)"
}
엔터티 유형은 속성 이름이 아니라 URL에 있는 엔터티 세트에서 추론됩니다. 이 예외는 개발자들이 Dynamics 통합을 예측하기 어려운 이유 중 하나입니다.
개발자들이 말하는 내용
StackOverflow나 Dynamics 포럼을 검색하면 같은 질문이 반복해서 나타납니다:
- 왜 API가
ownerid대신_ownerid_value를 반환하나요? - 왜 일부 조회는
@odata.bind가 필요하고, 다른 조회는field_entity@odata.bind가 필요하나요? - 읽기와 쓰기에 따라 필드 이름이 왜 바뀌나요?
토론에서 흔히 보이는 패턴은 개발자들이 명확한 문서보다 시도와 오류를 통해 올바른 형식을 찾아낸다는 것입니다. API는 수년간 진화해 온 플랫폼 아키텍처를 반영하고 있으며, 그 복잡성이 통합 계층에 누출됩니다.
왜 이것이 통합에 중요한가
Dynamics와 통합을 구축하고 있다면—특히 동기화 엔진, SaaS 커넥터, 데이터 파이프라인—이 복잡성이 빠르게 누적됩니다. 통합 코드는 결국 다음을 처리하게 됩니다:
- 다형성 조회 감지
- 엔터티 유형 해석
- OData 바인딩 형식
- 다양한 명명 규칙
- 응답 주석
더 간단한 접근법: 표준 CRM 모델
Aurinko에서 표준 CRM API에 대한 MS Dynamics 지원을 마무리하고 있습니다. 주요 목표 중 하나는 개발자 경험에서 이러한 플랫폼‑특정 특이점을 제거하는 것입니다.
_ownerid_value 또는 ownerid@odata.bind를 다루는 대신, 개발자는 다음과 같이 간단히 사용할 수 있습니다:
owner.idowner.typeowner.name
Aurinko가 백그라운드에서 무거운 작업을 처리합니다:
- 다형성 조회 해석
- 엔터티 유형 감지
- OData 바인딩 로직
- Dynamics 명명 규칙
- 스키마 불일치
그 결과 CRM 플랫폼 전반에 걸쳐 깔끔하고 일관된 모델이 제공되어, 통합 코드가 각 API의 특이점을 이해할 필요가 없습니다.
Final thoughts
Microsoft Dynamics는 믿을 수 없을 정도로 강력한 플랫폼이지만, 그 API는 대규모 엔터프라이즈 시스템의 복잡성을 반영합니다.
| Context | Field Name |
|---|---|
| Metadata | ownerid |
| Read | _ownerid_value |
| Write | ownerid@odata.bind |
다형성 접미사 규칙과 주석을 추가하면 개발자들이 왜 종종 압도감을 느끼는지 쉽게 알 수 있습니다. 이러한 세부 사항을 추상화함으로써 배관 작업보다 비즈니스 로직에 집중할 수 있습니다.
Our goal with Aurinko is simple: make CRM integrations feel predictable again—and sometimes that starts by hiding _ownerid_value forever.