Dodawanie wielu wierszy do bazy danych

0

Cześć,
piszę aplikację z użyciem C# i SQL Server. Tworzę metody CRUD dotyczące klientów i ich pracowników (każdy klient może mieć ich wiele). Mam funkcję dodającą pracownika do bazy:

public static void Pracownik_Add(int klientId, Pracownik pracownik){
    SqlConnection conn = new SqlConnection()...

    if (conn.State == ConnectionState.Closed) conn.Open();

    SqlCommand cmd = new SqlCommand("INSERT INTO kl_klienciPracownicy (klient_id, imie, nazwisko) VALUES (@klient_id, ....);", conn);
    cmd.Parameters.AddWithValue("@klient_id", klientId);
    cmd.Parameters.AddWithValue("@imie", pracownik.Imie);
    ...

    cmd.ExecuteNonQuery();

    if (conn.State == ConnectionState.Open) conn.Close();
}

Używam jej, gdy user dodaje pracownika do istniejącego już klienta (za pomocą dialogu edycji)

Problem jednak znajduje się w sytuacji, gdy klient jest dopiero dodawany. Używam do tego metody:

public static void Klient_Add(Klient klient){
      SqlConnection conn = new ....

      SqlCommand cmdKlientAdd = new SqlCommand("INSERT INTO kl_klienci (imie, nazwisko) OUTPUT INSERTED.ID VALUES (...);", conn);

      int klientId = (int)cmdKlientAdd.ExecuteScalar();

      // Dodałem już klienta i mam jego id. Chcę teraz dodać pracowników z nim powiązanym. Wymyśliłem dwa podejścia:

      // 1. Działa, ale raczej obciąża bazę

      foreach (Pracownik prac in klient.Pracownicy){ // gdzie klient.Pracownicy to lista
          Pracownik_Add(klientId, prac);
      }

      // 2. Też działa, ale mam wrażenie, że można to zrobić lepiej:

      StringBuilder sb = new StringBuilder("INSERT INTO kl_klienciPracownicy (klient_id, imie, nazwisko) VALUES ");
      List<SqlParameter> parameters = new List<SqlParameter>();
      int iloscWierszy = klient.Pracownicy.Count;

      for (int i = 0; i < iloscWierszy; i++){
          sb.Append($"(@klient_id, @imie{i}, @nazwisko{i})");
          parameters.Add(new SqlParameter($"@imie{i}", klient.Pracownicy[i].Imie));
          ...

          if (i != iloscWierszy - 1) sb.Append(",");
      }

      SqlCommand cmdPracownicyAdd = new SqlCommand(sb.ToString(), conn);
      cmdPracownicyAdd.Parameters.AddWithValue("@klient_id", klientId);
      cmdPracownicyAdd.Parameters.AddRange(parameters.ToArray());

      cmdPracownicyAdd.ExecuteNonQuery();

      ...
}

Które rozwiązanie jest lepsze? Czy może jest jeszcze jakiś inny sposób?

Z góry dzięki

1

Spróbuj sobie sposobu gdzie trzymasz SQL w pliku w projekcie i parametry oznaczasz tam np. {Parametr} u w kodzie robisz tylko sobie replace na danym parametr. Dzięki temu zachowasz pliki SQL w jednym miejscu z parametrami które potem wygodnie użyjesz w kodzie i łatwo dodasz nowe.
Szukaj info pod how to parametrize sql in c#

2

Możesz użyć SqlBulkCopy
Definiujesz dataTable

DataTable pracownicyTable = new DataTable();
pracownicyTable.Columns.Add("Imie", typeof(string));
// albo sobie to uprościć jeśli jest dużo kolumn
foreach (PropertyInfo property in typeof(Pracownik).GetProperties())
{
    pracownicyTable.Columns.Add(new DataColumn() { ColumnName = property.Name, DataType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType, AllowDBNull = true });
}

Dodajesz pracowników

foreach (var pracownik in pracownicy)
{
    DataRow nowyPracownik = pracownicyTable.NewRow();
    nowyPracownik["Imie"] = pracownik.Imie;
    // Albo uprościć jeśli dużo propertisów
    foreach (PropertyInfo property in typeof(Pracownik).GetProperties()
    {
        nowyPracownik[property.Name] = pracownik.GetType().GetProperty(property.Name)?.GetValue(pracownik, null) ?? DBNull.Value;
    }
    pracownicyTable.Rows.Add(nowyPracownik);
}

I dodanie do bazy

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn))
    {
        bulkCopy.DestinationTableName = "Pracownicy";
        bulkCopy.ColumnMappings.Add("Imie", "Imie");
        // ...
        bulkCopy.WriteToServer(pracownicyTable);
    }
}
0

Dzięki : )

0

A najlepiej użyj jakiegoś ORM (najprościej EF) i wykonaj to wszystko na obiektach, nie gołym sql.

A tak z nieco innej bajki - mieszanie polskiego z angielskim drastycznie zmniejsza czytelność kodu. To samo odnosi się do bazy danych. Ponadto w C# używa się składni CamelCase.

1 użytkowników online, w tym zalogowanych: 0, gości: 1