Patch 함수

적용 대상: 캔버스 앱 Copilot Studio Desktop 흐름 모델 기반 앱 Power Platform CLI Dataverse 함수

데이터 원본레코드를 하나 이상 수정 또는 생성하거나 데이터 원본 외부의 레코드를 병합합니다.

함수를 Patch 사용하여 사용자 상호 작용이 필요하지 않은 업데이트를 수행하거나 여러 화면에 걸쳐 있는 양식을 사용하는 경우와 같이 복잡한 상황에서 레코드를 수정할 수 있습니다.

간단한 변경을 위해 데이터 원본의 레코드를 더 쉽게 업데이트하려면 Edit form 컨트롤을 대신 사용합니다. Edit form 컨트롤을 추가하면 사용자에게 양식을 제공하여 채운 다음 데이터 원본에 변경 내용을 저장합니다. 자세한 내용은 데이터 양식 이해를 참조하십시오.

이 비디오를 통해 함수를 사용하는 방법을 알아보세요.Patch

Overview

함수를 Patch 사용하여 데이터 원본의 레코드를 하나 이상 수정합니다. 특정 필드 의 값을 업데이트하면서도 다른 속성에는 영향을 주지 않습니다. 예를 들어 다음 수식은 Contoso라는 고객의 전화 번호를 변경합니다.

Patch( Customers, LookUp( Customers, Name = "Contoso" ), { Phone: "1-212-555-1234" } )

Patch 함수와 함께 사용하여 레코드를 만듭니다. 이 동작을 사용하여 레코드를 만들고 편집할 수 있는 단일 화면을 만듭니다. 예를 들어 다음 수식은 Contoso라는 고객의 레코드를 만듭니다.

Patch( Customers, Defaults( Customers ), { Name: "Contoso" } )

Note

기본 값을 가진 데이터 소스의 레코드를 사용해 컬렉션을 패치하면, 패치 작업은 지정된 패치 값과 데이터 소스의 기본 값 모두로 컬렉션을 업데이트합니다. 패치 문장의 DataSource와 Defaults 함수의 DataSource가 일치해야 새 레코드가 생성됩니다.

데이터 원본으로 작업하지 않더라도 둘 이상의 레코드를 병합하는 데 사용할 Patch 수 있습니다. 예를 들어 다음 수식은 Contoso의 전화 번호와 위치를 식별하는 두 개의 레코드를 하나로 병합합니다.

Patch( { Name: "Contoso", Phone: "1-212-555-1234" }, { Name: "Contoso", Location: "Midtown" } )

Description

데이터 원본의 레코드 수정 또는 만들기

이 함수를 데이터 원본과 함께 사용하려면 데이터 원본을 지정한 다음, 기본 레코드를 지정합니다.

  • 레코드를 수정하려면 기본 레코드가 데이터 소스에서 가져와야 합니다. 갤러리의 Items 속성을 통해 기본 레코드를 얻거나, 컨텍스트 변수에 넣거나, 다른 경로를 통해 얻을 수도 있습니다. 하지만 기본 기록을 데이터 소스까지 추적할 수 있어야 합니다. 이 요건은 기록에 추가 정보가 포함되어 있어 수정 시 기록을 다시 찾는 데 도움이 되기 때문에 중요합니다.
  • 레코드를 만들려면 Defaults 함수를 사용하여 기본값으로 기본 레코드를 만듭니다.

그런 다음, 기본 레코드의 속성 값을 재정의하는 새 속성이 포함된 변경 레코드를 하나 이상 지정합니다. 변경 레코드는 인수 목록의 처음부터 끝까지 순서대로 처리되며, 이후 속성 값이 이전 속성 값보다 우선합니다.

반환 값 Patch 은 수정하거나 만든 레코드입니다. 레코드를 만든 경우 반환 값에는 데이터 원본이 자동으로 생성한 속성이 포함될 수 있습니다. 그러나 반환 값은 관련 테이블의 필드에 대한 값을 제공하지 않습니다.

예를 들어 Set(MyAccount, Patch(Accounts, First(Account), 'Account Name': "Example name"));MyAccount.'Primary Contact'.'Full Name'을 사용하는 경우. 이 경우 전체 이름을 산출할 수 없습니다. 대신 관련 테이블의 필드에 액세스하려면 다음과 같은 별도의 조회를 사용합니다.

LookUp(Accounts, Account = MyAccount.Account).'Primary Contact'.'Full Name'

데이터 원본을 업데이트할 때 하나 이상의 문제가 발생할 수 있습니다. 오류 처리에서 설명한 대로 IfErrorPatch를 반환 값 과 함께 사용하여 오류를 검색하고 응답합니다. 또한 Errors 함수를 사용하여 데이터 원본 작업의 설명과 같이 문제를 식별하고 검사할 수 있습니다.

관련 함수에는 전체 레코드를 바꾸려면 Update 함수와 레코드를 만드는 데 사용할 수 있는 Collect 함수가 있습니다. UpdateIf 함수를 사용하여 조건에 따라 여러 레코드의 특정 속성을 수정할 수 있습니다.

데이터 원본의 레코드 집합 수정 또는 만들기

또한 한 번의 통화로 여러 레코드를 생성하거나 수정할 수도 있습니다 Patch .

단일 기본 레코드를 전달하는 대신, 두 번째 인자에 기본 레코드 테이블을 제공하세요. 변경 기록도 기본 레코드와 1:1로 대응하는 테이블로 제공하세요. 각 변경 테이블의 레코드 수는 기본 테이블의 레코드 수와 동일해야 합니다.

이렇게 사용하면 Patch 반환 값이 기본 및 변경 레코드와 1:1로 대응하는 테이블이 됩니다.

데이터 원본 외부에서 레코드 병합

병합할 둘 이상의 레코드를 지정합니다. 이 함수는 인수 목록의 시작부터 끝까지 기록을 처리하며, 이후 속성 값이 이전 값보다 우선합니다.

Patch 는 병합된 레코드를 반환하며 데이터 원본에서 해당 인수 또는 레코드를 수정하지 않습니다.

Syntax

데이터 원본의 레코드 수정 또는 만들기

Patch( DataSource, BaseRecord, ChangeRecord1 [, ChangeRecord2, ... ])

  • DataSource – 필수 항목입니다. 수정할 레코드를 포함하거나 만들려는 레코드가 포함될 데이터 원본입니다.
  • BaseRecord – 필수입니다. 수정하거나 만들 레코드입니다. 레코드가 데이터 소스에서 왔다면, 함수는 레코드를 찾아 수정합니다. Defaults 결과를 사용하면 함수가 레코드를 생성합니다. 새 레코드를 만들려면 패치 문의 DataSource와 Defaults 함수의 DataSource가 일치해야 합니다.
  • ChangeRecords – 필수. BaseRecord에서 수정할 속성이 포함된 하나 이상의 레코드입니다. 이 함수는 인수 목록의 시작부터 끝까지 변경 레코드를 처리하며, 이후 속성 값이 이전 값보다 우선합니다.

데이터 원본의 레코드 집합 수정 또는 만들기

Patch( DataSource, BaseRecordsTable, ChangeRecordTable1 [, ChangeRecordTable2, ... ] )

  • DataSource – 필수 항목입니다. 수정할 레코드를 포함하거나 만들려는 레코드가 포함될 데이터 원본입니다.
  • BaseRecordTable – 필수. 수정하거나 만들 레코드 테이블입니다. 레코드가 데이터 소스에서 왔다면, 함수는 레코드를 찾아 수정합니다. Defaults 결과를 사용하면 함수가 레코드를 생성합니다. 새 레코드를 만들려면 패치 문의 DataSource와 Defaults 함수의 DataSource가 일치해야 합니다.
  • ChangeRecordTables – 필수. BaseRecordTable의 각 레코드에 대해 수정할 속성이 포함된 하나 이상의 레코드 테이블입니다. 이 함수는 인수 목록의 시작부터 끝까지 변경 레코드를 처리하며, 이후 속성 값이 이전 값보다 우선합니다.

Merge records

Patch( Record1, Record2 [, ...] )

  • 기록 - 필수. 병합할 둘 이상의 레코드입니다. 이 함수는 인자 목록의 시작부터 끝까지 기록을 순서대로 처리하며, 이후의 속성 값은 이전 값보다 우선합니다.

Examples

데이터 원본의 레코드 수정 또는 만들기

이 예시들에서는 IceCream이라는 데이터 소스에서 레코드를 수정하거나 생성합니다. 데이터 소스는 이 테이블 의 데이터를 포함하며 ID의 값을 자동으로 생성합니다:

맛과 양을 보여주는 IceCream 데이터 소스 예제 표의 스크린샷입니다.

이 데이터 소스의 메모리 버전을 생성하여 다음 예제들을 시도하려면 다음 공식을 평가해 보세요:

ClearCollect( IceCream,
    { ID: 1, Flavor: "Chocolate", Quantity: 100 },
    { ID: 2, Flavor: "Vanilla", Quantity: 200 }
)
Formula Description Result
Patch(아이스크림,
LookUp( 아이스크림, 맛 = "초콜릿" ), { 수량: 400 } )
IceCream 데이터 원본의 레코드를 수정합니다.
  • 수정할 레코드의 ID 열에는 값 1이 포함됩니다. (Chocolate 레코드가 이 ID를 갖습니다.)
  • Quantity 열의 값이 400으로 변경됩니다.
{ ID: 1, 맛: "초콜릿", 수량: 400 }

아이스크림 데이터 소스의 초콜릿 항목이 수정되었습니다.
Patch( IceCream, Defaults( IceCream), { Flavor: "Strawberry" } ) IceCream 데이터 원본에 레코드를 만듭니다.
  • ID 열에는 데이터 원본이 자동으로 생성한 값 3이 있습니다.
  • Quantity 열에는 Defaults 함수가 지정한 대로 IceCream 데이터 원본의 해당 열에 대한 기본값인 0이 있습니다.
  • Flavor 열에는 Strawberry라는 값이 있습니다.
{ ID: 3, 맛: "딸기", 수량: 0 }

아이스크림 데이터 소스에 딸기 항목이 생성됩니다.

이전 공식들을 평가한 후, 데이터 소스는 다음과 같은 값으로 끝납니다:

공식이 Patch 평가된 후 IceCream 데이터 소스의 스크린샷입니다.

데이터 원본 외부에서 레코드 병합

Formula Description Result
Patch( { 이름: "제임스", 점수: 90 }, { 이름: "짐", 합격: 진짜 } ) 데이터 원본 외부의 두 레코드를 병합합니다.
  • 각 레코드의 Name 열 값은 일치하지 않습니다. 결과에는 인수 목록의 시작에 더 가까운 레코드의 값(James) 대신 인수 목록의 끝에 더 가까운 레코드의 값(Jim)이 포함됩니다.
  • 첫 번째 레코드에 두 번째 레코드에 없는 열(Score)이 포함되어 있습니다. 결과에는 이 열이 해당하는 값(90)과 함께 포함됩니다.
  • 두 번째 레코드에 첫 번째 레코드에 없는 열(Passed)이 포함되어 있습니다. 결과에는 이 열이 해당하는 값(true)과 함께 포함됩니다.
{ 이름: "Jim", Score: 90, Passed: true }

레코드 집합을 수정하거나 생성하기(데이터 소스에서)

단일 레코드 대신 테이블로 사용하면 Patch 한 번의 호출에서 여러 레코드를 생성하거나 수정할 수 있습니다. 반환 값은 입력 테이블과 1:1로 대응하는 레코드 테이블입니다.

이 예시는 아이스크림 데이터 소스에서 여러 맛의 수량을 동시에 업데이트합니다:

Patch(
    IceCream,
    Table(
        { ID: 1, Flavor: "Chocolate", Quantity: 150 },
        { ID: 2, Flavor: "Vanilla", Quantity: 200 }
    ),
    Table(
        { Quantity: 300 },
        { Quantity: 400 }
    )
)

결과는 업데이트된 기록이 포함된 표입니다: { ID: 1, Flavor: "Chocolate", Quantity: 300 }{ ID: 2, Flavor: "Vanilla", Quantity: 400 }.

이 예시는 Defaults를 사용하여 여러 개의 새 레코드를 생성합니다:

Patch(
    IceCream,
    Table( Defaults( IceCream ), Defaults( IceCream ) ),
    Table(
        { Flavor: "Mint", Quantity: 60 },
        { Flavor: "Peach", Quantity: 80 }
    )
)

Note

테이블과 함께 사용할 Patch 때, 각 변경 테이블의 레코드 수가 기본 테이블의 레코드 수와 일치해야 합니다. 그렇지 않으면 오류가 발생합니다.

여러 레코드를 수정할 때 오류를 감지하려면 IfError를 사용하세요. IfError 선호되는 메커니즘이며 Power Fx 호스트 전반에 걸쳐 작동합니다:

IfError(
    Patch(
        IceCream,
        baseRecords,
        changeRecords
    ),
    Notify( "Some records failed to update: " & FirstError.Message, NotificationType.Error )
)

Patch Dataverse 컬럼 타입과 함께

다음 예시들은 Microsoft Dataverse 데이터 소스에 구체적으로 적용됩니다. 레코드 형태는 데이터 소스에 따라 다릅니다(예: SharePoint와 SQL Server는 서로 다른 형식을 가지고 있습니다).

선택 열: 선택 열을 설정하려면 열거 값을 직접 사용하세요. 이 예시는 계정 테이블에 상태 선택 열을 설정합니다:

Patch(
    Accounts,
    LookUp( Accounts, 'Account Name' = "Contoso" ),
    { 'Status': 'Status (Accounts)'.Active }
)

조회 칼럼: Lookup 열을 설정하려면 관련 테이블의 기본 키를 가진 레코드를 제공합니다. 이 예시는 계정 기록에 대한 주요 연락처 조회를 설정합니다:

Patch(
    Accounts,
    LookUp( Accounts, 'Account Name' = "Contoso" ),
    { 'Primary Contact': LookUp( Contacts, 'Full Name' = "John Smith" ) }
)

Note

이 열형 예시는 Dataverse 전용입니다. SharePoint나 SQL Server와 같은 다른 데이터 소스는 유사한 열 유형에 대해 서로 다른 레코드 형태를 요구할 수 있습니다. 정확한 형식은 해당 데이터 소스의 문서를 참조하시기 바랍니다.

다음과 같은 공식에서의 위임 Patch

Patch 함수 자체는 데이터 소스에 쿼리하는 대신 쓰기 때문에 위임의 대상이 아닙니다. 하지만 공식의 레코드 선택 부분(예: Filter, LookUp, ForAll)이 데이터 소스 위임 한도를 초과하는 쿼리를 포함할 경우 위임 경고가 발생할 Patch 수 있습니다.

위임 경고가 포함된 공식 Patch에서 보면, 그 경고가 데이터 검색 함수 Patch 에 적용되는지 확인해 보세요. 위임에 관한 자세한 내용은 '캔버스 앱에서의 위임 이해'를 참조하세요.

함수의 Patch 흔한 오류

이 기능을 사용할 Patch 때 데이터 소스 연결성, 권한 또는 데이터 충돌로 인해 오류가 발생할 수 있습니다. IfErrorIsError를 사용해 오류를 감지하고 적절히 대응하세요.

  • "함수 사용 Patch 시 네트워크 오류": 이 오류는 일반적으로 앱이 데이터 소스에 접근할 수 없음을 나타냅니다. 일반적인 원인으로는 인터넷 연결이 끊기거나, 데이터 소스가 일시적으로 사용 불가하거나, 현재 사용자의 권한 부족 등이 있습니다. IfError로 통화를 Patch 감싸 사용자에게 의미 있는 메시지를 제공합니다.

  • "서버의 변경 사항에 충돌이 존재한다": 이 오류는 앱이 레코드를 읽고 변경 사항을 쓰기 사이에 다른 사용자나 프로세스가 동일한 레코드를 수정할 때 발생합니다. Refresh 함수를 호출하여 데이터 소스를 새로고침하고 연산을 다시 시도하세요.

  • 권한 오류: 사용자가 데이터 소스에서 레코드를 생성하거나 수정할 권한이 없으면 호출이 Patch 실패합니다. IfError를 사용해 권한 관련 오류를 포착하고 사용자를 안내하세요.

일반적인 오류 처리 패턴에 대해서는 오류 처리를 참조하세요.

As 또는 ThisRecord 사용

수식에 AThisRecord 키워드를 사용하여 모호한 평가 맥락을 피하세요.

다음 예시에서 명제의 If 첫 번째 Lookup 예시를 고려하자. (OrderID = A[@OrderID])범위 내 LookupOrderIdOrderId 수집 AForAll 범위 내 비교가 기대됩니다. 이 경우에는 국소 매개변수로 해석하는 것이 좋습니다 A[@OrderId] . 하지만 모호하다.

Power Apps 현재 왼쪽 OrderId와 오른쪽 A[@OrderId] 모두를 Lookup 범위의 장으로 해석합니다. 따라서 Lookup 는 항상 첫 [dbo].[Orders1] 번째 행을 찾는데, 이는 조건이 항상 참이기 때문이다(즉, 임의의 행 는 OrderId 자기 자신과 같다).

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]',
            OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]',
                OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

As 또는 ThisRecord 사용

가능하다면 As 연산자나 ThisRecord 키워드를 사용하여 왼쪽 부분을 명확히 하세요. 앞선 시나리오에 권장되는 방법입니다.

공식이 여러 스코프ForAll를 사용하고, FilterLookup 같은 데이터 소스나 테이블에서 사용할 경우, 스코프 파라미터가 다른 필드와 충돌할 수 있습니다. 따라서 필드 이름을 해석하고 모호함을 피하기 위해 As 연산자나 ThisRecord 를 사용하세요.

예를 들어, 다음 예시에서 As 연산자를 사용해 중의성을 구분할 수 있습니다.

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]' As B,
            B.OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]' As C,
                C.OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

또는 ThisRecord를 같은 목적으로 사용할 수도 있습니다.

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]',
            ThisRecord.OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]',
                ThisRecord.OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

As 연산자와 ThisRecord의 사용에 대해 더 알고 싶다면 Operators 문서를 참조하세요.