Repository: amp-labs/connectors
Pull request #672 (2024-07-09 18:26:36)

fix: DynamicsCRM ListObjectMetadata accepts plural ObjectName
# Changes

Plural object name is used in Read method. And therefore ListObjectMetadata will act the same way. 
However, under the hood it will keep making single name lookup in XML.

Mock tests: I changed the Entities used in sample XML file. There is no schema of collection/list but only schemas of items.

# Manual Tests

## Read

Only plural works (some entities appear in mock tests):

Read("chat") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/f05e4b59-e621-4f81-9eb3-012614e9ba29)
Read("chats") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/a1a2a459-0cac-4355-b058-82ecf2aa6456)

Read("fax") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/edaea7e7-e2c9-48b9-9bf7-9b434cfc7818)
Read("faxes") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/0764a9f3-2fc6-47cb-9282-d21c4d197521)

Read("contact") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/bbab0df7-56a2-456f-a0b9-3dff4952f8e9)
Read("contacts") => 
![image](https://github.com/amp-labs/connectors/assets/60330780/919f4f8c-c709-4618-9f67-1be4f4162ba4)

## ListObjectMetadata
Accounts is supplied to both Read and ListObjectMetadata. 
Read output matches against metadata schema.
![image](https://github.com/amp-labs/connectors/assets/60330780/9ac27d63-7ef0-4f1b-8109-6334a022d56d)

## Write+Delete
Works as before.
![image](https://github.com/amp-labs/connectors/assets/60330780/6571beb8-43c9-40ef-8783-a7ecb66e4dcf)






Patch:
diff --git a/common/naming/plural.go b/common/naming/plural.go
index fe5b7813..dc2be9a0 100644
--- a/common/naming/plural.go
+++ b/common/naming/plural.go
@@ -32,7 +32,7 @@ func NewPluralStrings(list []string) PluralStrings {
 	return result
 }
 
-func (s PluralStrings) Plural() SingularStrings {
+func (s PluralStrings) Singular() SingularStrings {
 	result := make(SingularStrings, len(s))
 	for i, str := range s {
 		result[i] = str.Singular()
diff --git a/dynamicscrm/metadata.go b/dynamicscrm/metadata.go
index 874fcbbd..5d019c8b 100644
--- a/dynamicscrm/metadata.go
+++ b/dynamicscrm/metadata.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 
 	"github.com/amp-labs/connectors/common"
+	"github.com/amp-labs/connectors/common/naming"
 	"github.com/amp-labs/connectors/common/xquery"
 )
 
@@ -21,6 +22,12 @@ var (
 // so the ListObjectMetadataResult will have display names that look like "accountleads".
 func (c *Connector) ListObjectMetadata(
 	ctx context.Context, objectNames []string,
+) (*common.ListObjectMetadataResult, error) {
+	return c.listObjectMetadata(ctx, naming.NewSingularStrings(objectNames))
+}
+
+func (c *Connector) listObjectMetadata(
+	ctx context.Context, objectNames naming.SingularStrings,
 ) (*common.ListObjectMetadataResult, error) {
 	// Ensure that objectNames is not empty
 	if len(objectNames) == 0 {
@@ -103,13 +110,18 @@ func extractEntities(root *xquery.XML) (EntitySet, error) {
 
 // Select entities that match entity names of interest.
 // Every property has display identical to itself.
-func convertEntitySetToMetadataSet(names []string, entities EntitySet) (map[string]common.ObjectMetadata, error) {
+func convertEntitySetToMetadataSet(
+	names naming.SingularStrings, entities EntitySet,
+) (map[string]common.ObjectMetadata, error) {
 	result := map[string]common.ObjectMetadata{}
 
 	for _, name := range names {
-		entity, ok := entities[name]
+		nameStrSingle := name.String()
+
+		entity, ok := entities[nameStrSingle]
+
 		if !ok {
-			return nil, fmt.Errorf("unknown entity %v %w", name, ErrObjectNotFound)
+			return nil, fmt.Errorf("unknown entity %v %w", nameStrSingle, ErrObjectNotFound)
 		}
 
 		properties := entity.GetAllProperties()
@@ -119,8 +131,9 @@ func convertEntitySetToMetadataSet(names []string, entities EntitySet) (map[stri
 			fieldsMap[p] = p
 		}
 
-		result[name] = common.ObjectMetadata{
-			DisplayName: name,
+		nameStrPlural := name.Plural().String()
+		result[nameStrPlural] = common.ObjectMetadata{
+			DisplayName: nameStrPlural,
 			FieldsMap:   fieldsMap,
 		}
 	}


Test patch:
diff --git a/dynamicscrm/metadata_test.go b/dynamicscrm/metadata_test.go
index ea4d3d7b..4da99587 100644
--- a/dynamicscrm/metadata_test.go
+++ b/dynamicscrm/metadata_test.go
@@ -21,13 +21,13 @@ func TestListObjectMetadata(t *testing.T) { // nolint:funlen,gocognit,cyclop
 	fakeServerResp := mockutils.DataFromFile(t, "metadata.xml")
 
 	tests := []struct {
-		name                string
-		input               []string
-		server              *httptest.Server
-		connector           Connector
-		expected            *common.ListObjectMetadataResult
-		expectedFieldsCount map[string]int // used instead of `expected` when response result is too big
-		expectedErrs        []error
+		name         string
+		input        []string
+		server       *httptest.Server
+		connector    Connector
+		comparator   func(serverURL string, actual, expected *common.ListObjectMetadataResult) bool
+		expected     *common.ListObjectMetadataResult
+		expectedErrs []error
 	}{
 		{
 			name:  "At least one object name must be queried",
@@ -79,35 +79,50 @@ func TestListObjectMetadata(t *testing.T) { // nolint:funlen,gocognit,cyclop
 		},
 		{
 			name:  "Correctly list metadata for account leads and invite contact",
-			input: []string{"accountleads", "adx_invitation_invitecontacts"},
+			input: []string{"chats", "faxes"},
 			server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/xml")
 				w.WriteHeader(http.StatusOK)
 				_, _ = w.Write(fakeServerResp)
 			})),
+			comparator: func(baseURL string, actual, expected *common.ListObjectMetadataResult) bool {
+				return mockutils.MetadataResultComparator.SubsetFields(actual, expected)
+			},
 			expected: &common.ListObjectMetadataResult{
 				Result: map[string]common.ObjectMetadata{
-					"accountleads": {
-						DisplayName: "accountleads",
+					"faxes": {
+						DisplayName: "faxes",
 						FieldsMap: map[string]string{
-							"accountid":                 "accountid",
-							"accountleadid":             "accountleadid",
-							"importsequencenumber":      "importsequencenumber",
-							"leadid":                    "leadid",
-							"name":                      "name",
-							"overriddencreatedon":       "overriddencreatedon",
-							"timezoneruleversionnumber": "timezoneruleversionnumber",
-							"utcconversiontimezonecode": "utcconversiontimezonecode",
-							"versionnumber":             "versionnumber",
+							"tsid":                 "tsid",
+							"numberofpages":        "numberofpages",
+							"coverpagename":        "coverpagename",
+							"overriddencreatedon":  "overriddencreatedon",
+							"subcategory":          "subcategory",
+							"billingcode":          "billingcode",
+							"subscriptionid":       "subscriptionid",
+							"importsequencenumber": "importsequencenumber",
+							"directioncode":        "directioncode",
+							"faxnumber":            "faxnumber",
+							"category":             "category",
 						},
 					},
-					"adx_invitation_invitecontacts": {
-						DisplayName: "adx_invitation_invitecontacts",
+					"chats": {
+						DisplayName: "chats",
 						FieldsMap: map[string]string{
-							"adx_invitation_invitecontactsid": "adx_invitation_invitecontactsid",
-							"adx_invitationid":                "adx_invitationid",
-							"contactid":                       "contactid",
-							"versionnumber":                   "versionnumber",
+							"modifiedinteamson":                "modifiedinteamson",
+							"_linkedby_value":                  "_linkedby_value",
+							"_unlinkedby_value":                "_unlinkedby_value",
+							"teamschatid":                      "teamschatid",
+							"eventssummary":                    "eventssummary",
+							"importsequencenumber":             "importsequencenumber",
+							"overriddencreatedon":              "overriddencreatedon",
+							"linkedon":                         "linkedon",
+							"unlinkedon":                       "unlinkedon",
+							"lastsyncerror":                    "lastsyncerror",
+							"modifiedinteamsbyactivitypartyid": "modifiedinteamsbyactivitypartyid",
+							"syncstatus":                       "syncstatus",
+							"formattedscheduledstart":          "formattedscheduledstart",
+							"statuscode":                       "statuscode",
 						},
 					},
 				},
@@ -121,16 +136,19 @@ func TestListObjectMetadata(t *testing.T) { // nolint:funlen,gocognit,cyclop
 			// activitypointer 	(has 58 fields), which in turn inherits from
 			// crmbaseentity 	(has 0 fields)
 			name:  "Correctly list metadata for phone calls including inherited fields",
-			input: []string{"phonecall", "activitypointer", "crmbaseentity"},
+			input: []string{"phonecalls", "activitypointers", "crmbaseentities"},
 			server: httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 				w.Header().Set("Content-Type", "application/xml")
 				w.WriteHeader(http.StatusOK)
 				_, _ = w.Write(fakeServerResp)
 			})),
-			expectedFieldsCount: map[string]int{
-				"phonecall":       65,
-				"activitypointer": 58,
-				"crmbaseentity":   0,
+			comparator: func(baseURL string, actual, expected *common.ListObjectMetadataResult) bool {
+				// we are comparing if number of fields match under ListObjectMetadataResult.Result
+				return compareFieldCount(map[string]int{
+					"phonecalls":       65,
+					"activitypointers": 58,
+					"crmbaseentities":  0,
+				}, actual)
 			},
 			expectedErrs: nil,
 		},
@@ -176,29 +194,33 @@ func TestListObjectMetadata(t *testing.T) { // nolint:funlen,gocognit,cyclop
 			}
 
 			// compare desired output
-			// there are 2 modes we can compare, by exact field values or matching quantity
-			if len(tt.expectedFieldsCount) != 0 {
-				// we are comparing if number of fields match under ListObjectMetadataResult.Result
-				for entityName, count := range tt.expectedFieldsCount {
-					entity, ok := output.Result[entityName]
-					if !ok {
-						t.Fatalf("%s: expected entity was missing: (%v)", tt.name, entityName)
-					}
+			var ok bool
+			if tt.comparator == nil {
+				// default comparison is concerned about all fields
+				ok = reflect.DeepEqual(output, tt.expected)
+			} else {
+				ok = tt.comparator(tt.server.URL, output, tt.expected)
+			}
 
-					got := len(entity.FieldsMap)
-					if got != count {
-						t.Fatalf("%s: expected entity '%v' to have (%v) fields got: (%v)",
-							tt.name, entityName, count, got)
-					}
-				}
-			} else { // nolint:gocritic
-				// usual comparison of ListObjectMetadataResult
-				if !reflect.DeepEqual(output, tt.expected) {
-					diff := deep.Equal(output, tt.expected)
-					t.Fatalf("%s:, \nexpected: (%v), \ngot: (%v), \ndiff: (%v)",
-						tt.name, tt.expected, output, diff)
-				}
+			if !ok {
+				diff := deep.Equal(output, tt.expected)
+				t.Fatalf("%s:, \nexpected: (%v), \ngot: (%v), \ndiff: (%v)", tt.name, tt.expected, output, diff)
 			}
 		})
 	}
 }
+
+func compareFieldCount(expectedFieldsCount map[string]int, actual *common.ListObjectMetadataResult) bool {
+	for entityName, count := range expectedFieldsCount {
+		if entity, ok := actual.Result[entityName]; !ok {
+			return false
+		} else {
+			got := len(entity.FieldsMap)
+			if got != count {
+				return false
+			}
+		}
+	}
+
+	return true
+}
diff --git a/dynamicscrm/test/metadata.xml b/dynamicscrm/test/metadata.xml
index 4308e0f7..e0904a40 100644
--- a/dynamicscrm/test/metadata.xml
+++ b/dynamicscrm/test/metadata.xml
@@ -11,39 +11,6 @@
     <edmx:DataServices>
         <Schema Namespace="Microsoft.Dynamics.CRM" Alias="mscrm" xmlns="http://docs.oasis-open.org/odata/ns/edm">
             <EntityType Name="crmbaseentity" Abstract="true"/>
-            <EntityType Name="accountleads" BaseType="mscrm.crmbaseentity">
-                <Key>
-                    <PropertyRef Name="accountleadid"/>
-                </Key>
-                <Property Name="importsequencenumber" Type="Edm.Int32"/>
-                <Property Name="accountleadid" Type="Edm.Guid"/>
-                <Property Name="name" Type="Edm.String" Unicode="false"/>
-                <Property Name="accountid" Type="Edm.Guid"/>
-                <Property Name="overriddencreatedon" Type="Edm.DateTimeOffset"/>
-                <Property Name="versionnumber" Type="Edm.Int64"/>
-                <Property Name="leadid" Type="Edm.Guid"/>
-                <Property Name="timezoneruleversionnumber" Type="Edm.Int32"/>
-                <Property Name="utcconversiontimezonecode" Type="Edm.Int32"/>
-                <NavigationProperty Name="accountleads_AsyncOperations" Type="Collection(mscrm.asyncoperation)"
-                                    Partner="regardingobjectid_accountleads"/>
-                <NavigationProperty Name="accountleads_MailboxTrackingFolders"
-                                    Type="Collection(mscrm.mailboxtrackingfolder)"
-                                    Partner="regardingobjectid_accountleads"/>
-                <NavigationProperty Name="accountleads_BulkDeleteFailures" Type="Collection(mscrm.bulkdeletefailure)"
-                                    Partner="regardingobjectid_accountleads"/>
-                <NavigationProperty Name="accountleads_PrincipalObjectAttributeAccesses"
-                                    Type="Collection(mscrm.principalobjectattributeaccess)"
-                                    Partner="objectid_accountleads"/>
-            </EntityType>
-            <EntityType Name="adx_invitation_invitecontacts" BaseType="mscrm.crmbaseentity">
-                <Key>
-                    <PropertyRef Name="adx_invitation_invitecontactsid"/>
-                </Key>
-                <Property Name="adx_invitationid" Type="Edm.Guid"/>
-                <Property Name="versionnumber" Type="Edm.Int64"/>
-                <Property Name="contactid" Type="Edm.Guid"/>
-                <Property Name="adx_invitation_invitecontactsid" Type="Edm.Guid"/>
-            </EntityType>
             <EntityType Name="phonecall" BaseType="mscrm.activitypointer">
                 <Key>
                     <PropertyRef Name="activityid"/>
@@ -55,171 +22,7 @@
                 <Property Name="subscriptionid" Type="Edm.Guid"/>
                 <Property Name="phonenumber" Type="Edm.String" Unicode="false"/>
                 <Property Name="importsequencenumber" Type="Edm.Int32"/>
-                <NavigationProperty Name="phonecall_PostRegardings" Type="Collection(mscrm.postregarding)"
-                                    Partner="regardingobjectid_phonecall"/>
-                <NavigationProperty Name="phonecall_PostFollows" Type="Collection(mscrm.postfollow)"
-                                    Partner="regardingobjectid_phonecall"/>
-                <NavigationProperty Name="regardingobjectid_knowledgebaserecord_phonecall"
-                                    Type="mscrm.knowledgebaserecord"
-                                    Nullable="false" Partner="KnowledgeBaseRecord_PhoneCalls"/>
-                <NavigationProperty Name="phonecall_actioncard" Type="Collection(mscrm.actioncard)"
-                                    Partner="regardingobjectid_phonecall_actioncard"/>
-                <NavigationProperty Name="transactioncurrencyid_phonecall" Type="mscrm.transactioncurrency"
-                                    Nullable="false"
-                                    Partner="TransactionCurrency_PhoneCall"/>
-                <NavigationProperty Name="regardingobjectid_contact_phonecall" Type="mscrm.contact" Nullable="false"
-                                    Partner="Contact_Phonecalls"/>
-                <NavigationProperty Name="sla_phonecall_sla" Type="mscrm.sla" Nullable="false"
-                                    Partner="manualsla_phonecall"/>
-                <NavigationProperty Name="PhoneCall_BulkDeleteFailures" Type="Collection(mscrm.bulkdeletefailure)"
-                                    Partner="regardingobjectid_phonecall"/>
-                <NavigationProperty Name="modifiedonbehalfby_phonecall" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_phonecall_modifiedonbehalfby"/>
-                <NavigationProperty Name="PhoneCall_AsyncOperations" Type="Collection(mscrm.asyncoperation)"
-                                    Partner="regardingobjectid_phonecall"/>
-                <NavigationProperty Name="regardingobjectid_account_phonecall" Type="mscrm.account" Nullable="false"
-                                    Partner="Account_Phonecalls"/>
-                <NavigationProperty Name="createdby_phonecall" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_phonecall_createdby"/>
-                <NavigationProperty Name="createdonbehalfby_phonecall" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_phonecall_createdonbehalfby"/>
-                <NavigationProperty Name="phonecall_activity_parties" Type="Collection(mscrm.activityparty)"
-                                    Partner="activityid_phonecall"/>
-                <NavigationProperty Name="PhoneCall_ProcessSessions" Type="Collection(mscrm.processsession)"
-                                    Partner="regardingobjectid_phonecall"/>
-                <NavigationProperty Name="owningbusinessunit_phonecall" Type="mscrm.businessunit" Nullable="false"
-                                    Partner="business_unit_phone_call_activities"/>
-                <NavigationProperty Name="PhoneCall_DuplicateMatchingRecord" Type="Collection(mscrm.duplicaterecord)"
-                                    Partner="duplicaterecordid_phonecall"/>
-                <NavigationProperty Name="regardingobjectid_knowledgearticle_phonecall" Type="mscrm.knowledgearticle"
-                                    Nullable="false" Partner="KnowledgeArticle_Phonecalls"/>
-                <NavigationProperty Name="stageid_processstage" Type="mscrm.processstage" Nullable="false"
-                                    Partner="processstage_phonecalls"/>
-                <NavigationProperty Name="PhoneCall_DuplicateBaseRecord" Type="Collection(mscrm.duplicaterecord)"
-                                    Partner="baserecordid_phonecall"/>
-                <NavigationProperty Name="phonecall_connections1" Type="Collection(mscrm.connection)"
-                                    Partner="record1id_phonecall"/>
-                <NavigationProperty Name="activityid_activitypointer" Type="mscrm.activitypointer" Nullable="false"
-                                    Partner="activity_pointer_phonecall"/>
-                <NavigationProperty Name="slakpiinstance_phonecall" Type="Collection(mscrm.slakpiinstance)"
-                                    Partner="regarding_phonecall"/>
-                <NavigationProperty Name="slainvokedid_phonecall_sla" Type="mscrm.sla" Nullable="false"
-                                    Partner="sla_phonecall"/>
-                <NavigationProperty Name="PhoneCall_SyncErrors" Type="Collection(mscrm.syncerror)"
-                                    Partner="regardingobjectid_phonecall_syncerror"/>
-                <NavigationProperty Name="modifiedby_phonecall" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_phonecall_modifiedby"/>
-                <NavigationProperty Name="owningteam_phonecall" Type="mscrm.team" Nullable="false"
-                                    Partner="team_phonecall"/>
-                <NavigationProperty Name="PhoneCall_QueueItem" Type="Collection(mscrm.queueitem)"
-                                    Partner="objectid_phonecall"/>
-                <NavigationProperty Name="PhoneCall_Annotation" Type="Collection(mscrm.annotation)"
-                                    Partner="objectid_phonecall"/>
-                <NavigationProperty Name="phonecall_connections2" Type="Collection(mscrm.connection)"
-                                    Partner="record2id_phonecall"/>
-                <NavigationProperty Name="owninguser_phonecall" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="user_phonecall"/>
-                <NavigationProperty Name="phonecall_principalobjectattributeaccess"
-                                    Type="Collection(mscrm.principalobjectattributeaccess)"
-                                    Partner="objectid_phonecall"/>
-                <NavigationProperty Name="ownerid_phonecall" Type="mscrm.principal" Nullable="false"
-                                    Partner="owner_phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_adx_invitation_phonecall" Type="mscrm.adx_invitation"
-                                    Nullable="false"
-                                    Partner="adx_invitation_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_adplacement_phonecall" Type="mscrm.mspp_adplacement"
-                                    Nullable="false" Partner="mspp_adplacement_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_pollplacement_phonecall"
-                                    Type="mscrm.mspp_pollplacement"
-                                    Nullable="false" Partner="mspp_pollplacement_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_publishingstatetransitionrule_phonecall"
-                                    Type="mscrm.mspp_publishingstatetransitionrule" Nullable="false"
-                                    Partner="mspp_publishingstatetransitionrule_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_redirect_phonecall" Type="mscrm.mspp_redirect"
-                                    Nullable="false"
-                                    Partner="mspp_redirect_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_shortcut_phonecall" Type="mscrm.mspp_shortcut"
-                                    Nullable="false"
-                                    Partner="mspp_shortcut_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_mspp_website_phonecall" Type="mscrm.mspp_website"
-                                    Nullable="false"
-                                    Partner="mspp_website_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_lead_phonecall" Type="mscrm.lead" Nullable="false"
-                                    Partner="Lead_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_bookableresourcebooking_phonecall"
-                                    Type="mscrm.bookableresourcebooking"
-                                    Nullable="false" Partner="bookableresourcebooking_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_bookableresourcebookingheader_phonecall"
-                                    Type="mscrm.bookableresourcebookingheader" Nullable="false"
-                                    Partner="bookableresourcebookingheader_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_bulkoperation_phonecall" Type="mscrm.bulkoperation"
-                                    Nullable="false"
-                                    Partner="BulkOperation_Phonecall"/>
-                <NavigationProperty Name="regardingobjectid_campaign_phonecall" Type="mscrm.campaign" Nullable="false"
-                                    Partner="Campaign_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_campaignactivity_phonecall" Type="mscrm.campaignactivity"
-                                    Nullable="false" Partner="CampaignActivity_Phonecalls"/>
-                <NavigationProperty Name="phonecall_campaignresponse" Type="Collection(mscrm.campaignresponse)"
-                                    Partner="originatingactivityid_phonecall"/>
-                <NavigationProperty Name="regardingobjectid_contract_phonecall" Type="mscrm.contract" Nullable="false"
-                                    Partner="Contract_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_entitlement_phonecall" Type="mscrm.entitlement"
-                                    Nullable="false"
-                                    Partner="entitlement_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_entitlementtemplate_phonecall"
-                                    Type="mscrm.entitlementtemplate"
-                                    Nullable="false" Partner="entitlementtemplate_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_incident_phonecall" Type="mscrm.incident" Nullable="false"
-                                    Partner="Incident_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_site_phonecall" Type="mscrm.site" Nullable="false"
-                                    Partner="site_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_customerasset_phonecall"
-                                    Type="mscrm.msdyn_customerasset"
-                                    Nullable="false" Partner="msdyn_customerasset_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_playbookinstance_phonecall"
-                                    Type="mscrm.msdyn_playbookinstance"
-                                    Nullable="false" Partner="msdyn_playbookinstance_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_invoice_phonecall" Type="mscrm.invoice" Nullable="false"
-                                    Partner="Invoice_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_opportunity_phonecall" Type="mscrm.opportunity"
-                                    Nullable="false"
-                                    Partner="Opportunity_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_quote_phonecall" Type="mscrm.quote" Nullable="false"
-                                    Partner="Quote_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_salesorder_phonecall" Type="mscrm.salesorder"
-                                    Nullable="false"
-                                    Partner="SalesOrder_Phonecalls"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_postalbum_phonecall" Type="mscrm.msdyn_postalbum"
-                                    Nullable="false"
-                                    Partner="msdyn_postalbum_PhoneCalls"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_swarm_phonecall" Type="mscrm.msdyn_swarm"
-                                    Nullable="false"
-                                    Partner="msdyn_swarm_PhoneCalls"/>
-                <NavigationProperty Name="msdyn_phonecall_msdyn_transcript_transcripttarget"
-                                    Type="Collection(mscrm.msdyn_transcript)"
-                                    Partner="msdyn_transcripttarget_phonecall"/>
-                <NavigationProperty Name="msdyn_phonecall_msdyn_ocrecording_recordingtarget"
-                                    Type="Collection(mscrm.msdyn_ocrecording)"
-                                    Partner="msdyn_recordingtarget_phonecall"/>
-                <NavigationProperty Name="msdyn_phonecall_msdyn_conversationinsight_conversationinsighttarget"
-                                    Type="Collection(mscrm.msdyn_conversationinsight)"
-                                    Partner="msdyn_conversationinsighttarget_phonecall"/>
-                <NavigationProperty Name="msdyn_msdyn_conversationactionitem_phonecall_msdyn_createdactivity"
-                                    Type="Collection(mscrm.msdyn_conversationactionitem)"
-                                    Partner="msdyn_createdactivity_phonecall"/>
-                <NavigationProperty Name="msdyn_msdyn_sciconversation_phonecall_msdyn_relatedactivity"
-                                    Type="Collection(mscrm.msdyn_sciconversation)"
-                                    Partner="msdyn_relatedactivity_phonecall"/>
-                <NavigationProperty Name="msdyn_phonecall_msdyn_recording_phone_call_activity"
-                                    Type="Collection(mscrm.msdyn_recording)" Partner="msdyn_phone_call_activity"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_salessuggestion_phonecall"
-                                    Type="mscrm.msdyn_salessuggestion"
-                                    Nullable="false" Partner="msdyn_salessuggestion_PhoneCalls"/>
-                <NavigationProperty Name="msdyn_msdyn_salescopilotinsight_phonecall_msdyn_activityid"
-                                    Type="Collection(mscrm.msdyn_salescopilotinsight)"
-                                    Partner="msdyn_activityid_phonecall"/>
-                <NavigationProperty Name="serviceid_phonecall" Type="mscrm.service" Nullable="false"
-                                    Partner="service_phonecalls"/>
+                <!-- Navigation properties are omitted -->
             </EntityType>
             <EntityType Name="activitypointer" BaseType="mscrm.crmbaseentity" Abstract="true">
                 <Key>
@@ -283,296 +86,43 @@
                 <Property Name="sortdate" Type="Edm.DateTimeOffset"/>
                 <Property Name="timezoneruleversionnumber" Type="Edm.Int32"/>
                 <Property Name="utcconversiontimezonecode" Type="Edm.Int32"/>
-                <NavigationProperty Name="regardingobjectid_new_interactionforemail" Type="mscrm.interactionforemail"
-                                    Nullable="false"
-                                    Partner="new_interactionforemail_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="interactionforemailid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_knowledgebaserecord" Type="mscrm.knowledgebaserecord"
-                                    Nullable="false"
-                                    Partner="KnowledgeBaseRecord_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="knowledgebaserecordid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_account" Type="mscrm.account" Nullable="false"
-                                    Partner="Account_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="accountid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="createdby" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_activitypointer_createdby">
-                    <ReferentialConstraint Property="_createdby_value" ReferencedProperty="systemuserid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_contact" Type="mscrm.contact" Nullable="false"
-                                    Partner="Contact_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="contactid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_socialactivity" Type="Collection(mscrm.socialactivity)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_recurringappointmentmaster"
-                                    Type="Collection(mscrm.recurringappointmentmaster)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_email" Type="Collection(mscrm.email)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="sendermailboxid" Type="mscrm.mailbox" Nullable="false"
-                                    Partner="activitypointer_sendermailboxid_mailbox">
-                    <ReferentialConstraint Property="_sendermailboxid_value" ReferencedProperty="mailboxid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="transactioncurrencyid" Type="mscrm.transactioncurrency" Nullable="false"
-                                    Partner="TransactionCurrency_ActivityPointer">
-                    <ReferentialConstraint Property="_transactioncurrencyid_value"
-                                           ReferencedProperty="transactioncurrencyid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="ActivityPointer_QueueItem" Type="Collection(mscrm.queueitem)"
-                                    Partner="objectid_activitypointer"/>
-                <NavigationProperty Name="ownerid" Type="mscrm.principal" Nullable="false"
-                                    Partner="owner_activitypointers">
-                    <ReferentialConstraint Property="_ownerid_value" ReferencedProperty="ownerid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="owninguser" Type="mscrm.systemuser" Nullable="false" Partner="user_activity">
-                    <ReferentialConstraint Property="_owninguser_value" ReferencedProperty="systemuserid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="sla_activitypointer_sla" Type="mscrm.sla" Nullable="false"
-                                    Partner="manualsla_activitypointer">
-                    <ReferentialConstraint Property="_slaid_value" ReferencedProperty="slaid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="owningbusinessunit" Type="mscrm.businessunit" Nullable="false"
-                                    Partner="business_unit_activitypointer">
-                    <ReferentialConstraint Property="_owningbusinessunit_value" ReferencedProperty="businessunitid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_knowledgearticle" Type="mscrm.knowledgearticle"
-                                    Nullable="false"
-                                    Partner="KnowledgeArticle_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="knowledgearticleid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="modifiedonbehalfby" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_activitypointer_modifiedonbehalfby">
-                    <ReferentialConstraint Property="_modifiedonbehalfby_value" ReferencedProperty="systemuserid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_activity_mime_attachment"
-                                    Type="Collection(mscrm.activitymimeattachment)"
-                                    Partner="objectid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_fax" Type="Collection(mscrm.fax)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="createdonbehalfby" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_activitypointer_createdonbehalfby">
-                    <ReferentialConstraint Property="_createdonbehalfby_value" ReferencedProperty="systemuserid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="modifiedby" Type="mscrm.systemuser" Nullable="false"
-                                    Partner="lk_activitypointer_modifiedby">
-                    <ReferentialConstraint Property="_modifiedby_value" ReferencedProperty="systemuserid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_task" Type="Collection(mscrm.task)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_phonecall" Type="Collection(mscrm.phonecall)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_appointment" Type="Collection(mscrm.appointment)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_letter" Type="Collection(mscrm.letter)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activitypointer_connections2" Type="Collection(mscrm.connection)"
-                                    Partner="record2id_activitypointer"/>
-                <NavigationProperty Name="slakpiinstance_activitypointer" Type="Collection(mscrm.slakpiinstance)"
-                                    Partner="regarding_activitypointer"/>
-                <NavigationProperty Name="owningteam" Type="mscrm.team" Nullable="false" Partner="team_activity">
-                    <ReferentialConstraint Property="_owningteam_value" ReferencedProperty="teamid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="ActivityPointer_BulkDeleteFailures" Type="Collection(mscrm.bulkdeletefailure)"
-                                    Partner="regardingobjectid_activitypointer"/>
-                <NavigationProperty Name="slainvokedid_activitypointer_sla" Type="mscrm.sla" Nullable="false"
-                                    Partner="sla_activitypointer">
-                    <ReferentialConstraint Property="_slainvokedid_value" ReferencedProperty="slaid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activitypointer_connections1" Type="Collection(mscrm.connection)"
-                                    Partner="record1id_activitypointer"/>
-                <NavigationProperty Name="ActivityPointer_AsyncOperations" Type="Collection(mscrm.asyncoperation)"
-                                    Partner="regardingobjectid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_recurrencerule" Type="Collection(mscrm.recurrencerule)"
-                                    Partner="objectid"/>
-                <NavigationProperty Name="activitypointer_activity_parties" Type="Collection(mscrm.activityparty)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_chat" Type="Collection(mscrm.chat)"
-                                    Partner="activityid_chat"/>
-                <NavigationProperty Name="activitypointer_FileAttachments" Type="Collection(mscrm.fileattachment)"
-                                    Partner="objectid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_adx_invitation" Type="mscrm.adx_invitation" Nullable="false"
-                                    Partner="adx_invitation_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="adx_invitationid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_adx_inviteredemption"
-                                    Type="Collection(mscrm.adx_inviteredemption)"
-                                    Partner="activityid_adx_inviteredemption"/>
-                <NavigationProperty Name="activity_pointer_adx_portalcomment" Type="Collection(mscrm.adx_portalcomment)"
-                                    Partner="activityid_adx_portalcomment"/>
-                <NavigationProperty Name="regardingobjectid_mspp_adplacement" Type="mscrm.mspp_adplacement"
-                                    Nullable="false"
-                                    Partner="mspp_adplacement_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="mspp_adplacementid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_mspp_pollplacement" Type="mscrm.mspp_pollplacement"
-                                    Nullable="false"
-                                    Partner="mspp_pollplacement_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="mspp_pollplacementid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_mspp_publishingstatetransitionrule"
-                                    Type="mscrm.mspp_publishingstatetransitionrule" Nullable="false"
-                                    Partner="mspp_publishingstatetransitionrule_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="mspp_publishingstatetransitionruleid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_mspp_redirect" Type="mscrm.mspp_redirect" Nullable="false"
-                                    Partner="mspp_redirect_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="mspp_redirectid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_mspp_shortcut" Type="mscrm.mspp_shortcut" Nullable="false"
-                                    Partner="mspp_shortcut_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="mspp_shortcutid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_mspp_website" Type="mscrm.mspp_website" Nullable="false"
-                                    Partner="mspp_website_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="mspp_websiteid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_lead" Type="mscrm.lead" Nullable="false"
-                                    Partner="Lead_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="leadid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_bookableresourcebooking"
-                                    Type="mscrm.bookableresourcebooking"
-                                    Nullable="false" Partner="bookableresourcebooking_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="bookableresourcebookingid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_bookableresourcebookingheader"
-                                    Type="mscrm.bookableresourcebookingheader"
-                                    Nullable="false" Partner="bookableresourcebookingheader_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="bookableresourcebookingheaderid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_BulkOperation" Type="Collection(mscrm.bulkoperation)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_campaign" Type="mscrm.campaign" Nullable="false"
-                                    Partner="Campaign_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="campaignid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_campaignactivity" Type="Collection(mscrm.campaignactivity)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_campaignresponse" Type="Collection(mscrm.campaignresponse)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_BulkOperation_logs" Type="Collection(mscrm.bulkoperationlog)"
-                                    Partner="bulkoperationid_activitypointer"/>
-                <NavigationProperty Name="CreatedActivity_BulkOperationLogs" Type="Collection(mscrm.bulkoperationlog)"
-                                    Partner="createdobjectid_activitypointer"/>
-                <NavigationProperty Name="ActivityPointer_CampaignActivityItems"
-                                    Type="Collection(mscrm.campaignactivityitem)"
-                                    Partner="campaignactivityid"/>
-                <NavigationProperty Name="activity_campaignresponse" Type="Collection(mscrm.campaignresponse)"
-                                    Partner="originatingactivityid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_campaignactivity" Type="mscrm.campaignactivity"
-                                    Nullable="false"
-                                    Partner="CampaignActivity_ActivityPointers"/>
-                <NavigationProperty Name="regardingobjectid_bulkoperation" Type="mscrm.bulkoperation" Nullable="false"
-                                    Partner="BulkOperation_ActivityPointers"/>
-                <NavigationProperty Name="regardingobjectid_entitlement" Type="mscrm.entitlement" Nullable="false"
-                                    Partner="entitlement_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="entitlementid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_entitlementtemplate" Type="mscrm.entitlementtemplate"
-                                    Nullable="false"
-                                    Partner="entitlementtemplate_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="entitlementtemplateid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_site" Type="mscrm.site" Nullable="false"
-                                    Partner="site_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="siteid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_msdyn_customerasset" Type="mscrm.msdyn_customerasset"
-                                    Nullable="false"
-                                    Partner="msdyn_customerasset_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="msdyn_customerassetid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_msdyn_playbookinstance" Type="mscrm.msdyn_playbookinstance"
-                                    Nullable="false"
-                                    Partner="msdyn_playbookinstance_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="msdyn_playbookinstanceid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_invoice" Type="mscrm.invoice" Nullable="false"
-                                    Partner="Invoice_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="invoiceid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_opportunity" Type="mscrm.opportunity" Nullable="false"
-                                    Partner="Opportunity_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="opportunityid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_opportunity_close" Type="Collection(mscrm.opportunityclose)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_order_close" Type="Collection(mscrm.orderclose)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="activity_pointer_quote_close" Type="Collection(mscrm.quoteclose)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_quote" Type="mscrm.quote" Nullable="false"
-                                    Partner="Quote_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="quoteid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="regardingobjectid_salesorder" Type="mscrm.salesorder" Nullable="false"
-                                    Partner="SalesOrder_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="salesorderid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="msdyn_readtracker_poly_activitypointer"
-                                    Type="Collection(mscrm.msdyn_readtracker)"
-                                    Partner="msdyn_RegardingObjectId"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_postalbum" Type="mscrm.msdyn_postalbum"
-                                    Nullable="false"
-                                    Partner="msdyn_postalbum_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="msdyn_postalbumid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_msfp_alert" Type="Collection(mscrm.msfp_alert)"
-                                    Partner="activityid_msfp_alert"/>
-                <NavigationProperty Name="activity_pointer_msfp_surveyinvite" Type="Collection(mscrm.msfp_surveyinvite)"
-                                    Partner="activityid_msfp_surveyinvite"/>
-                <NavigationProperty Name="activity_pointer_msfp_surveyresponse"
-                                    Type="Collection(mscrm.msfp_surveyresponse)"
-                                    Partner="activityid_msfp_surveyresponse"/>
-                <NavigationProperty Name="activity_pointer_msdyn_copilottranscript"
-                                    Type="Collection(mscrm.msdyn_copilottranscript)"
-                                    Partner="activityid_msdyn_copilottranscript"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_swarm" Type="mscrm.msdyn_swarm" Nullable="false"
-                                    Partner="msdyn_swarm_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="msdyn_swarmid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_msdyn_ocliveworkitem"
-                                    Type="Collection(mscrm.msdyn_ocliveworkitem)"
-                                    Partner="activityid_msdyn_ocliveworkitem"/>
-                <NavigationProperty Name="activity_pointer_msdyn_ocsession" Type="Collection(mscrm.msdyn_ocsession)"
-                                    Partner="activityid_msdyn_ocsession"/>
-                <NavigationProperty Name="regardingobjectid_msdyn_salessuggestion" Type="mscrm.msdyn_salessuggestion"
-                                    Nullable="false"
-                                    Partner="msdyn_salessuggestion_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value"
-                                           ReferencedProperty="msdyn_salessuggestionid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_incident_resolution"
-                                    Type="Collection(mscrm.incidentresolution)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_incident" Type="mscrm.incident" Nullable="false"
-                                    Partner="Incident_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="incidentid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="serviceid" Type="mscrm.service" Nullable="false"
-                                    Partner="service_activity_pointers">
-                    <ReferentialConstraint Property="_serviceid_value" ReferencedProperty="serviceid"/>
-                </NavigationProperty>
-                <NavigationProperty Name="activity_pointer_service_appointment"
-                                    Type="Collection(mscrm.serviceappointment)"
-                                    Partner="activityid_activitypointer"/>
-                <NavigationProperty Name="regardingobjectid_contract" Type="mscrm.contract" Nullable="false"
-                                    Partner="Contract_ActivityPointers">
-                    <ReferentialConstraint Property="_regardingobjectid_value" ReferencedProperty="contractid"/>
-                </NavigationProperty>
+                <!-- Navigation properties are omitted -->
+            </EntityType>
+            <EntityType Name="chat" BaseType="mscrm.activitypointer">
+                <Key>
+                    <PropertyRef Name="activityid"/>
+                </Key>
+                <Property Name="modifiedinteamson" Type="Edm.DateTimeOffset"/>
+                <Property Name="_linkedby_value" Type="Edm.Guid"/>
+                <Property Name="_unlinkedby_value" Type="Edm.Guid"/>
+                <Property Name="teamschatid" Type="Edm.String" Unicode="false"/>
+                <Property Name="eventssummary" Type="Edm.String" Unicode="false"/>
+                <Property Name="importsequencenumber" Type="Edm.Int32"/>
+                <Property Name="overriddencreatedon" Type="Edm.DateTimeOffset"/>
+                <Property Name="linkedon" Type="Edm.DateTimeOffset"/>
+                <Property Name="unlinkedon" Type="Edm.DateTimeOffset"/>
+                <Property Name="lastsyncerror" Type="Edm.Int32"/>
+                <Property Name="modifiedinteamsbyactivitypartyid" Type="Edm.Guid"/>
+                <Property Name="syncstatus" Type="Edm.Int32"/>
+                <!-- Navigation properties are omitted -->
+            </EntityType>
+            <EntityType Name="fax" BaseType="mscrm.activitypointer">
+                <Key>
+                    <PropertyRef Name="activityid"/>
+                </Key>
+                <Property Name="tsid" Type="Edm.String" Unicode="false"/>
+                <Property Name="numberofpages" Type="Edm.Int32"/>
+                <Property Name="coverpagename" Type="Edm.String" Unicode="false"/>
+                <Property Name="overriddencreatedon" Type="Edm.DateTimeOffset"/>
+                <Property Name="subcategory" Type="Edm.String" Unicode="false"/>
+                <Property Name="billingcode" Type="Edm.String" Unicode="false"/>
+                <Property Name="subscriptionid" Type="Edm.Guid"/>
+                <Property Name="importsequencenumber" Type="Edm.Int32"/>
+                <Property Name="directioncode" Type="Edm.Boolean"/>
+                <Property Name="faxnumber" Type="Edm.String" Unicode="false"/>
+                <Property Name="category" Type="Edm.String" Unicode="false"/>
+                <!-- Navigation properties are omitted -->
             </EntityType>
         </Schema>
     </edmx:DataServices>
-</edmx:Edmx>
\ No newline at end of file
+</edmx:Edmx>
diff --git a/test/dynamicscrm/metadata/main.go b/test/dynamicscrm/metadata/main.go
index e541baa1..2e7cb47d 100644
--- a/test/dynamicscrm/metadata/main.go
+++ b/test/dynamicscrm/metadata/main.go
@@ -16,8 +16,7 @@ import (
 )
 
 var (
-	objectName     = "accounts"
-	objectNameMeta = "account"
+	objectName = "accounts"
 )
 
 // we want to compare fields returned by read and schema properties provided by metadata methods
@@ -52,7 +51,7 @@ func main() {
 	beforeCall := time.Now()
 
 	metadata, err := conn.ListObjectMetadata(ctx, []string{
-		objectNameMeta,
+		objectName,
 	})
 	if err != nil {
 		utils.Fail("error listing metadata for microsoft CRM", "error", err)
@@ -64,7 +63,7 @@ func main() {
 
 	data := sanitizeReadResponse(response.Data[0].Raw)
 
-	mismatchErr := mockutils.ValidateReadConformsMetadata(objectNameMeta, data, metadata)
+	mismatchErr := mockutils.ValidateReadConformsMetadata(objectName, data, metadata)
 	if mismatchErr != nil {
 		utils.Fail("schema and payload response have mismatching fields", "error", mismatchErr)
 	} else {
diff --git a/test/dynamicscrm/read/main.go b/test/dynamicscrm/read/main.go
index c7ab5e6a..740d7fa1 100644
--- a/test/dynamicscrm/read/main.go
+++ b/test/dynamicscrm/read/main.go
@@ -13,6 +13,10 @@ import (
 	"github.com/amp-labs/connectors/test/utils"
 )
 
+var (
+	objectName = "contacts"
+)
+
 func main() {
 	// Handle Ctrl-C gracefully.
 	ctx, done := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
@@ -30,7 +34,7 @@ func main() {
 	defer utils.Close(conn)
 
 	res, err := conn.Read(ctx, common.ReadParams{
-		ObjectName: "contacts",
+		ObjectName: objectName,
 		Fields: []string{
 			"fullname", "emailaddress1", "fax",
 		},
diff --git a/test/dynamicscrm/write-delete/main.go b/test/dynamicscrm/write-delete/main.go
index 4835b3f4..27252f77 100644
--- a/test/dynamicscrm/write-delete/main.go
+++ b/test/dynamicscrm/write-delete/main.go
@@ -14,6 +14,10 @@ import (
 	"github.com/amp-labs/connectors/test/utils/mockutils"
 )
 
+var (
+	objectName = "leads"
+)
+
 type LeadCreatePayload struct {
 	LastName    string `json:"lastname,omitempty"`
 	FirstName   string `json:"firstname,omitempty"`
@@ -101,7 +105,7 @@ func searchLead(res *common.ReadResult, key, value string) map[string]any {
 
 func readLeads(ctx context.Context, conn *dynamicscrm.Connector) *common.ReadResult {
 	res, err := conn.Read(ctx, common.ReadParams{
-		ObjectName: "leads",
+		ObjectName: objectName,
 		Fields: []string{
 			"leadid", "lastname", "firstname", "companyname", "subject",
 		},
@@ -115,7 +119,7 @@ func readLeads(ctx context.Context, conn *dynamicscrm.Connector) *common.ReadRes
 
 func createLead(ctx context.Context, conn *dynamicscrm.Connector, payload *LeadCreatePayload) {
 	res, err := conn.Write(ctx, common.WriteParams{
-		ObjectName: "leads",
+		ObjectName: objectName,
 		RecordId:   "",
 		RecordData: payload,
 	})
@@ -130,7 +134,7 @@ func createLead(ctx context.Context, conn *dynamicscrm.Connector, payload *LeadC
 
 func updateLead(ctx context.Context, conn *dynamicscrm.Connector, leadID string, payload *LeadUploadPayload) {
 	res, err := conn.Write(ctx, common.WriteParams{
-		ObjectName: "leads",
+		ObjectName: objectName,
 		RecordId:   leadID,
 		RecordData: payload,
 	})
@@ -145,7 +149,7 @@ func updateLead(ctx context.Context, conn *dynamicscrm.Connector, leadID string,
 
 func removeLead(ctx context.Context, conn *dynamicscrm.Connector, leadID string) {
 	res, err := conn.Delete(ctx, common.DeleteParams{
-		ObjectName: "leads",
+		ObjectName: objectName,
 		RecordId:   leadID,
 	})
 	if err != nil {
diff --git a/test/utils/mockutils/metadataResult.go b/test/utils/mockutils/metadataResult.go
index e131f941..8ef9b3b8 100644
--- a/test/utils/mockutils/metadataResult.go
+++ b/test/utils/mockutils/metadataResult.go
@@ -7,6 +7,41 @@ import (
 	"github.com/amp-labs/connectors/common"
 )
 
+var MetadataResultComparator = metadataResultComparator{}
+
+type metadataResultComparator struct{}
+
+// SubsetFields checks that expected ListObjectMetadataResult fields are a subset of actual metadata result.
+func (metadataResultComparator) SubsetFields(actual, expected *common.ListObjectMetadataResult) bool {
+	if len(expected.Result) == 0 {
+		invalidTest("please specify expected FieldsMap response")
+	}
+
+	for objectName, expectedMetadata := range expected.Result {
+		actualMetadata, ok := actual.Result[objectName]
+		if !ok {
+			return false
+		}
+
+		if actualMetadata.DisplayName != expectedMetadata.DisplayName {
+			return false
+		}
+
+		for k, v := range expectedMetadata.FieldsMap {
+			value, ok := actualMetadata.FieldsMap[k]
+			if !ok {
+				return false
+			}
+
+			if value != v {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
 // ValidateReadConformsMetadata this will check that all the fields that were returned by `Read` method
 // are a subset of ObjectMetadata. It is possible that Read will not return all the possible fields
 // which is fine and not a cause for an error.