Bibliotekom – zasadniczo – nie pomaga tajemniczość (o dezinformacji w temacie relacji)
W ADO.NET jest coś takiego jak możliwość ustanowienia relacji pomiędzy dwiema tabelami, a następnie prezentacja tabeli zależnej z kontekście nadrzędnej. Można to zrealizować np. tak:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
namespace DBTest
{
public partial class Form1 : Form
{
private SqlConnection conSQL = new SqlConnection();
private DataSet ds;
public Form1()
{
InitializeComponent();
}
private string MakeConnectionString()
{
conSQL.Close();
return "Persist Security Info=False;Data Source=.\\SQLEXPRESS2K8R2;Integrated Security=SSPI;";
}
private void MakeParameter(SqlCommand cmd, string Name, SqlDbType type, ParameterDirection pd, int size, string value)
{
SqlParameter p = cmd.Parameters.Add(Name, type);
if (size > 0) p.Size = size;
p.Direction = pd;
if (value == null) p.Value = System.DBNull.Value;
else p.Value = value;
}
private void button1_Click(object sender, EventArgs e)
{
if (conSQL.State != ConnectionState.Open)
{
conSQL.ConnectionString = MakeConnectionString();
conSQL.Open();
}
string SQL =
" create table #Elementy(id int, nazwa varchar(50));\n" +
" insert into #Elementy values (1, 'Pierwszy');\n" +
" insert into #Elementy values (2, 'Pierwszy dla pierwszego');\n" +
" insert into #Elementy values (3, 'Drugi dla pierwszego');\n" +
" insert into #Elementy values (4, 'Trzeci dla pierwszego');\n" +
" insert into #Elementy values (6, 'Drugi');\n" +
" insert into #Elementy values (7, 'Pierwszy dla drugiego');\n" +
" insert into #Elementy values (8, 'Drugi dla drugiego');\n" +
" create table #Składniki (id int identity(1, 1), ZestawId int, SkładnikId int);\n" +
" insert into #Składniki values (1, 2);\n" +
" insert into #Składniki values (1, 3);\n" +
" insert into #Składniki values (1, 4);\n" +
" insert into #Składniki values (6, 7);\n" +
" insert into #Składniki values (6, 8);\n" +
" select *\n" + // przekaż pełną listę elementów (zarówno składniki jak i zestawy)
" from #Elementy;\n" +
" select S.*, E.nazwa\n" + // przekaż jedynie składniki i ich związki z zestawami
" from #Składniki S\n" +
" inner join #Elementy E on E.id = S.SkładnikId;";
SqlCommand cmd = new SqlCommand(SQL, conSQL);
cmd.CommandType = CommandType.Text;
SqlDataAdapter da = new SqlDataAdapter(cmd);
ds = new DataSet(); // nowy obiekt na wyniki działania procedury
da.Fill(ds); // wypełnij obiekt wynikami
// ustanowienie relacji
ds.Relations.Add("relation", ds.Tables[0].Columns["id"], ds.Tables[1].Columns["ZestawId"]);
// przypisanie do gridów źródła danych
MainGrid.DataSource = ds;//.Tables[0];
DependendGrid.DataSource = ds;//.Tables[0];
// wkazanie elementu, którego dane mają być prezentowane
MainGrid.DataMember = ds.Tables[0].TableName;
// wkazanie elementu, którego dane mają być prezentowane
DependendGrid.DataMember = ds.Tables[0].TableName + ".relation";
}
}
}
Jest to kod aplikacji WinForms. Ostatnie dwie instrukcje metody button1_Click umożliwiają wskazanie danych, które mają zostać zaprezentowane na gridach. Zgodnie z definicją właściwości DataMember służy ona do wskazania (lub odczytania) nazwy listy lub tabeli, którą grid ma prezentować. Coś tu jednak nie gra. W ostatniej instrukcji nie jest bowiem wskazywana ani lista, ani tabela zawierająca dane. Jest wskazywana nazwa relacji. Co ciekawe występuje ona w kontekście nazwy tabeli, tej samej, której zawartość jest wyświetlana w MainGrid. A jednak koniec końców grid skądś wie, że ma wyświetlić nie tę właśnie tabelę, ale tabelę, która jest z nią w relacji i to jedynie w zakresie, jaki ta relacja w danej chwili definiuje. Proszę także zauważyć, że relacja został zdefiniowana w ramach DataSetu ds, a nie pierwszej jego tabeli. A jednak jest ona podawana właśnie w jej kontekście.
Przekopałem MSDN, aby odnaleźć jakieś informacje uzupełniające przeznaczenie właściwości DataMember i … nic. Wygląda na to, że jest to swojego rodzaju magiczna właściwość, której wszystkie możliwości nie są znane. Być może potrafi ona więcej cudownych rzeczy, niż tylko wskazywanie tabeli lub listy z danymi albo tabeli podrzędnej (w dodatku nie bezpośrednio, a przez wskazanie relacji). Pozostaje chyba zajrzeć do źródeł .NET, co pewnie w stosownym momencie uczynię. Na razie jednak „oczywistość” sposobu na prezentację zawartości tabeli zależnej będzie dla mnie niezgłębioną tajemnicą.