---
title: "混合バッチの取り扱い"
slug: "handling-mixed-batches"
abstract: "既知の接点でxDBを事前に埋め込み、新規および既存の接点のバッチを追加するシミュレーションを行うコンソールアプリケーションのサンプル。"
---
# 混合バッチの取り扱い

接続の追加や更新など、操作タイプの混合バッチは例外処理をより複雑にすることがあります。以下のシナリオを考えてみましょう。

-   CSVから2000件の連絡先がインポートされます
-   CSVには名前、Twitterユーザー名、メールアドレスなどの10のファセット情報が含まれています
-   連絡先は新しくなる場合もあれば既存の場合もあります
-   既存の連絡先がすでにファセットデータを持っている場合もあれば、そうでない場合もあります
-   輸入中に利益相反が生じることがあります

すべての連絡先がTwitterのユーザー名またはメールアドレスで識別されていると仮定します。以下の例では、除外される可能性を最小限に抑えるための決定がなされています:

-   既存の連絡先は、最初に .GetAsync<Contact> を呼び出して識別します。これはxConnectへの別の呼び出しですが、既存のレコードに対して新しい連絡先を作成しようとはしません。既存の識別子で新しい連絡先を作成すると例外が発生し、その場合は操作をやり直す必要があります。
-   連絡先が存在してもファセットデータが変わっていなければ、更新は送信しません。必須ではありません。
-   すべての「追加」および「更新」操作は依然として一括で提出されますが、例外が発生するリスクは最小限に抑えています。

## コンソールの例

以下のコンソールアプリケーション例を用いて以下が可能になります:

-   既知の連絡先でxDBを事前に埋め合わせてください。
-   新規および既存のコンタクトを一括に追加することをシミュレートします。

サンプルコンソールアプリケーションを使用するには:

1.  Visual Studioで新しいコンソールアプリケーションを作成します。
    
2.  Sitecoreフィードから以下のNuGetパッケージを追加してください:
    
    -   Sitecore.XConnect.Client
    -   Sitecore.XConnect.Collection.Model
    -   Sitecore.XConnect
3.  以下のコードをProgram.csに貼り付けてください:
    
    using Sitecore.XConnect;
    using Sitecore.XConnect.Client;
    using Sitecore.XConnect.Client.WebApi;
    using Sitecore.XConnect.Collection.Model;
    using Sitecore.XConnect.Schema;
    using Sitecore.Xdb.Common.Web;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Sitecore.XConnect.Operations;
    using Sitecore.Xdb.Common.Web;
    using Console = System.Console;
    using PersonalInformation = Sitecore.XConnect.Collection.Model.PersonalInformation;
    
    namespace Sitecore.Documentation
    {
     public class Program
     {
     private static int charcount = 20;
    
     private static void Main(string args)
     {
     MainAsync(args).ConfigureAwait(false).GetAwaiter().GetResult();
     Console.ForegroundColor = ConsoleColor.DarkGreen;
     Console.WriteLine("");
     Console.WriteLine("END OF PROGRAM.");
     Console.ReadKey();
     }
    
     private static async Task MainAsync(string args)
     {
     CertificateHttpClientHandlerModifierOptions options =
     CertificateHttpClientHandlerModifierOptions.Parse(
     "StoreName=My;StoreLocation=LocalMachine;FindType=FindByThumbprint;FindValue=5496B9D84850AFE5A3554B7B2D23F3B5C79CA53A");
    
     var certificateModifier = new CertificateHttpClientHandlerModifier(options);
    
     List<IHttpClientModifier> clientModifiers = new List<IHttpClientModifier>();
     var timeoutClientModifier = new TimeoutHttpClientModifier(new TimeSpan(0, 0, 20));
     clientModifiers.Add(timeoutClientModifier);
    
     var collectionClient = new CollectionWebApiClient(new Uri("https://tut4xconnect.dev.local/odata"),
     clientModifiers, new {certificateModifier});
     var searchClient = new SearchWebApiClient(new Uri("https://tut4xconnect.dev.local/odata"), clientModifiers,
     new {certificateModifier});
     var configurationClient = new ConfigurationWebApiClient(
     new Uri("https://tut4xconnect.dev.local/configuration"), clientModifiers, new {certificateModifier});
    
     var cfg = new XConnectClientConfiguration(
     new XdbRuntimeModel(CollectionModel.Model), collectionClient, searchClient, configurationClient);
    
     try
     {
     await cfg.InitializeAsync();
    
     // Print xConnect if configuration is valid
     var arr = new
     {
     @" \_\_\_\_\_\_ \_\_ ",
     @" / \\ | \\ ",
     @" \_\_ \_\_ | $$$$$$\\ \_\_\_\_\_\_ \_\_\_\_\_\_\_ \_\_\_\_\_\_\_ \_\_\_\_\_\_ \_\_\_\_\_\_\_ \_| $$\_ ",
     @"| \\ / \\| $$ \\$$ / \\ | \\ | \\ / \\ / \\| $$ \\ ",
     @"\\$$\\/ $$| $$ | $$$$$$\\| $$$$$$$\\| $$$$$$$\\| $$$$$$\\| $$$$$$$ \\$$$$$$ ",
     @" >$$ $$ | $$ \_\_ | $$ | $$| $$ | $$| $$ | $$| $$ $$| $$ | $$ \_\_ ",
     @" / $$$$\\ | $$\_\_/ \\| $$\_\_/ $$| $$ | $$| $$ | $$| $$$$$$$$| $$\_\_\_\_\_ | $$| \\",
     @"| $$ \\$$\\ \\$$ $$ \\$$ $$| $$ | $$| $$ | $$ \\$$ \\ \\$$ \\ \\$$ $$",
     @" \\$$ \\$$ \\$$$$$$ \\$$$$$$ \\$$ \\$$ \\$$ \\$$ \\$$$$$$$ \\$$$$$$$ \\$$$$ "
     };
     Console.WindowWidth = 160;
     foreach (string line in arr)
     Console.WriteLine(line);
    
     }
     catch (XdbModelConflictException ce)
     {
     Console.WriteLine("ERROR:" + ce.Message);
     return;
     }
    
     // Initialize a client using the validated configuration
     using (var client = new XConnectClient(cfg))
     {
     try
     {
     Console.WriteLine();
     Console.ForegroundColor = ConsoleColor.Yellow;
     Console.WriteLine("#############################################################################");
     Console.WriteLine("Prefill the xDB with some test data:");
     Console.WriteLine("#############################################################################");
     Console.WriteLine();
     Console.ForegroundColor = ConsoleColor.White;
    
     var newContacts = GenerateListOfPeople();
    
     Console.ForegroundColor = ConsoleColor.Green;
     Console.WriteLine("#############################################################################");
     Console.WriteLine("Contacts created in xDB:");
     Console.WriteLine("#############################################################################");
     Console.WriteLine();
     Console.ForegroundColor = ConsoleColor.White;
    
     Console.WriteLine(new string('-', charcount \* 4));
    
     foreach (var p in newContacts)
     {
     var newContact = new Contact();
     client.AddContactIdentifier(newContact,
     new ContactIdentifier(p.Source, p.Identifier, ContactIdentifierType.Known));
     client.SetFacet(newContact,
     new PersonalInformation() {FirstName = p.Firstname, LastName = p.LastName});
     client.AddContact(newContact);
    
     var row = p.Firstname.PadRight(charcount)
     + "| " + p.LastName.PadRight(charcount)
     + "| " + p.Identifier.PadRight(charcount)
     + "| " + p.Source.PadRight(charcount);
    
     Console.WriteLine(row);
     Console.WriteLine(new string('-', charcount \* 4));
     }
    
     Console.WriteLine();
    
     try
     {
     client.Submit();
     }
     catch (XdbExecutionException ex)
     {
     Console.WriteLine(ex.Message);
     }
    
     Console.ForegroundColor = ConsoleColor.Green;
     Console.WriteLine("#############################################################################");
     Console.WriteLine("Create contact data that you want to import - mix new and existing contacts!:");
     Console.WriteLine("#############################################################################");
     Console.ForegroundColor = ConsoleColor.White;
     Console.WriteLine();
    
     var newAndUpdatedContacts = GenerateListOfPeople();
    
     Console.ForegroundColor = ConsoleColor.Green;
     Console.WriteLine("#############################################################################");
     Console.WriteLine("Contact data to import:");
     Console.WriteLine("#############################################################################");
     Console.WriteLine();
     Console.ForegroundColor = ConsoleColor.White;
    
     Console.WriteLine(new string('-', charcount \* 4));
    
     foreach (var p in newAndUpdatedContacts)
     {
     var row = p.Firstname.PadRight(charcount)
     + "| " + p.LastName.PadRight(charcount)
     + "| " + p.Identifier.PadRight(charcount)
     + "| " + p.Source.PadRight(charcount);
    
     Console.WriteLine(row);
     Console.WriteLine(new string('-', charcount \* 4));
     }
    
     // Create identifiers from Identifier/Source properties so that we can retrieve contacts
     var identifiers = newAndUpdatedContacts.Select(x => new IdentifiedContactReference(x.Source, x.Identifier)).ToArray();
    
     // Retrieve all contacts using list of identifiers - make sure you also retrieve the PersonalInfo facet in the expand options,
     // as we want to write to these.
     var contactsTask = client.GetAsync<Contact>(identifiers, new ContactExecutionOptions( new ContactExpandOptions(PersonalInformation.DefaultFacetKey)));
    
     var contactResults = await contactsTask;
    
     if (contactResults != null && contactResults.Any())
     {
     foreach (var result in contactResults)
     {
     if (result.Exists)
     {
     // Get existing contact's identifiers
     var contactIdentifiers = result.Entity.Identifiers.Select(i => i.Identifier);
    
     var csvEntry = newAndUpdatedContacts.FirstOrDefault(p
    => result.Entity.Identifiers.Select(c => p.Identifier ==
    c.Identifier).FirstOrDefault());
    
     Console.WriteLine();
    
     Console.ForegroundColor = ConsoleColor.Cyan;
     Console.WriteLine("Updating existing contact: " + csvEntry.Identifier + "/" + csvEntry.Source);
     Console.ForegroundColor = ConsoleColor.White;
    
     if (csvEntry != null)
     {
     csvEntry.ContactExists = true;
    
     var personalInfoFacet =
     result.Entity.GetFacet<PersonalInformation>(PersonalInformation
     .DefaultFacetKey);
    
     if (personalInfoFacet != null)
     {
    
     Console.WriteLine("Contact has PersonalInformation facet.");
     // Check if facet is identical to what's in the CSV - if so, ignore. No need to send unnecessarny facet updates.
    
     bool FacetHasChanged = false;
    
     if (!Helpers.IsIdenticalOrEmptyOrNull(personalInfoFacet.FirstName,
     csvEntry.Firstname))
     {
     Console.WriteLine("First name was: " + personalInfoFacet.FirstName);
     personalInfoFacet.FirstName = csvEntry.Firstname;
     FacetHasChanged = true;
     Console.WriteLine("First name changed to: " + csvEntry.Firstname);
     }
    
     if (!Helpers.IsIdenticalOrEmptyOrNull(personalInfoFacet.LastName,
     csvEntry.LastName))
     {
     Console.WriteLine("Last name was: " + personalInfoFacet.LastName);
     personalInfoFacet.LastName = csvEntry.LastName;
     FacetHasChanged = true;
     Console.WriteLine("Last name changed to: " + csvEntry.LastName);
     }
    
     if (FacetHasChanged)
     {
     client.SetFacet<PersonalInformation>(result.Entity,
     PersonalInformation.DefaultFacetKey, personalInfoFacet);
     }
     else
     {
     Console.WriteLine("No facet data has changed.");
     }
     }
     else
     {
     Console.WriteLine("Contact does not have PersonalInfo facet - creating new facet.");
     // Set PersonalInfo facet data - note that we are not performing any validation; if first name and surname were not provided, those values will be null or empty.
     // This method adds a SetFacetOperation for each contact and adds it to the batch.
     client.SetFacet<PersonalInformation>(result.Entity,
     PersonalInformation.DefaultFacetKey, new PersonalInformation()
     {
     FirstName = csvEntry.Firstname,
     LastName = csvEntry.LastName
     });
     }
     }
     }
     }
     }
    
     // Now deal with new contacts
     foreach (var csvEntry in newAndUpdatedContacts.Where(x => !x.ContactExists))
     {
     Console.ForegroundColor = ConsoleColor.Cyan; ;
     Console.WriteLine("Creating new contact: " + csvEntry.Identifier + "/" + csvEntry.Source);
     Console.ForegroundColor = ConsoleColor.White;
    
     Console.WriteLine();
    
     // Create a new contact object for each row
     var contact = new Contact();
    
     // In this example, we have elected not to add contacts that do not have a Identifier naem
     if (!string.IsNullOrEmpty(csvEntry.Identifier))
     {
     // In this instance, Identifier names are the unique identifier.
     client.AddContactIdentifier(contact,
     new ContactIdentifier(csvEntry.Source, csvEntry.Identifier, ContactIdentifierType.Known));
    
     client.SetFacet<PersonalInformation>(contact, PersonalInformation.DefaultFacetKey,
     new PersonalInformation()
     {
     FirstName = csvEntry.Firstname,
     LastName = csvEntry.LastName
     });
    
     // Add the contact - this method creates an AddContactOperation for each contact and adds it to the batch.
     client.AddContact(contact);
     }
     }
    
     await client.SubmitAsync();
     }
     catch (XdbExecutionException ex)
     {
     // Handle conflicts that may have happened when udpating existing contacts
     var setPersonalOperations = ex.GetOperations(client)
     .OfType<SetFacetOperation<PersonalInformation>>()
     .Where(x => x.Result.Status == SaveResultStatus.Conflict);
    
     // Handle contacts that already exist
     var contactExists = ex.GetOperations(client).OfType<AddContactOperation>()
     .Where(x => x.Result.Status == SaveResultStatus.AlreadyExists);
     }
     }
     }
    
     private static List<Person> GenerateListOfPeople()
     {
     var contacts = new List<Person>();
     var createMoreContacts = true;
    
     string source = string.Empty;
     string identifier = string.Empty;
     string firstname = string.Empty;
     string lastname = string.Empty;
    
     int count = 1;
    
     while (createMoreContacts == true)
     {
     Console.ForegroundColor = ConsoleColor.Yellow;
     Console.WriteLine("Contact #" + count);
     Console.ForegroundColor = ConsoleColor.White;
     count++;
     Console.Write("Contact identifier source: ");
     source = Console.ReadLine();
     Console.Write("Contact identifier: ");
     identifier = Console.ReadLine();
     Console.Write("First name: ");
     firstname = Console.ReadLine();
     Console.Write("Last name: ");
     lastname = Console.ReadLine();
    
     var person = new Person()
     {
     Firstname = firstname,
     LastName = lastname,
     Identifier = identifier,
     Source = source
     };
    
     contacts.Add(person);
    
     Console.WriteLine();
     Console.Write("Create more contacts (Y/N)?: ");
     var createMore = Console.ReadLine();
     Console.WriteLine();
    
     if (createMore.ToLowerInvariant() == "n")
     {
     createMoreContacts = false;
     }
     }
     return contacts;
     }
     }
    
     public class Person
     {
     public string Firstname { get; set; }
     public string LastName { get; set; }
     public string Identifier { get; set; }
     public string Source { get; set; }
     public bool ContactExists { get; set; }
     }
    
     public static class Helpers
     {
     public static bool IsIdenticalOrEmptyOrNull(string current, string imported)
     {
     if (current.Equals(imported) || string.IsNullOrEmpty(imported))
     {
     return true;
     }
    
     return false;
     }
     }
    }
    
4.  サンプルのxConnectサービスURL(https://xconnect.dev.local/)を置き換えてください。
    
5.  証明書のサンプルを置き換えてください。証明書の指紋は <xconnect-root>\\App\_Config\\AppSettings.configファイルで見つけることができます。
    
6.  **F5**を押してアプリケーションを実行してください。以下の例はコンソールアプリケーションの出力を示しています:
    
    \_\_\_\_\_\_ \_\_
     / \\ | \\
     \_\_ \_\_ | $$$$$$\\ \_\_\_\_\_\_ \_\_\_\_\_\_\_ \_\_\_\_\_\_\_ \_\_\_\_\_\_ \_\_\_\_\_\_\_ \_| $$\_
    | \\ / \\| $$ \\$$ / \\ | \\ | \\ / \\ / \\| $$ \\
    \\$$\\/ $$| $$ | $$$$$$\\| $$$$$$$\\| $$$$$$$\\| $$$$$$\\| $$$$$$$ \\$$$$$$
     >$$ $$ | $$ \_\_ | $$ | $$| $$ | $$| $$ | $$| $$ $$| $$ | $$ \_\_
     / $$$$\\ | $$\_\_/ \\| $$\_\_/ $$| $$ | $$| $$ | $$| $$$$$$$$| $$\_\_\_\_\_ | $$| \\
    | $$ \\$$\\ \\$$ $$ \\$$ $$| $$ | $$| $$ | $$ \\$$ \\ \\$$ \\ \\$$ $$
     \\$$ \\$$ \\$$$$$$ \\$$$$$$ \\$$ \\$$ \\$$ \\$$ \\$$$$$$$ \\$$$$$$$ \\$$$$
    
    #############################################################################
    Prefill the xDB with some test data:
    #############################################################################
    
    Contact #1
    Contact identifier source: source45
    Contact identifier: mhwelander
    First name: Martina
    Last name: Welander
    
    Create more contacts (Y/N)?: Y
    
    Contact #2
    Contact identifier source: source45
    Contact identifier: myrtlesitecore
    First name: Myrtle
    Last name: Sitecore
    
    Create more contacts (Y/N)?: N
    
    #############################################################################
    Contacts created in xDB:
    #############################################################################
    
    --------------------------------------------------------------------------------
    Martina | Welander | mhwelander | source45
    --------------------------------------------------------------------------------
    Myrtle | Sitecore | myrtlesitecore | source45
    --------------------------------------------------------------------------------
    
    #############################################################################
    Create contact data that you want to import - mix new and existing contacts!:
    #############################################################################
    
    Contact #1
    Contact identifier source: source45
    Contact identifier: mhwelander
    First name: Martina Updated
    Last name: Welander Updated
    
    Create more contacts (Y/N)?: Y
    
    Contact #2
    Contact identifier source: source45
    Contact identifier: bobmcbob
    First name: Bob
    Last name: McBob
    
    Create more contacts (Y/N)?: N
    
    #############################################################################
    Contact data to import:
    #############################################################################
    
    --------------------------------------------------------------------------------
    Martina Updated | Welander Updated | mhwelander | source45
    --------------------------------------------------------------------------------
    Bob | McBob | bobmcbob | source45
    --------------------------------------------------------------------------------
    
    Updating existing contact: mhwelander/source45
    Contact has PersonalInformation facet.
    First name was: Martina
    First name changed to: Martina Updated
    Last name was: Welander
    Last name changed to: Welander Updated
    Creating new contact: bobmcbob/source45
    
    END OF PROGRAM.