I have a recurring problem with Data Tiers. Most entities have two important properties: ID and DisplayName. The id for the link and DisplayName for the text to show.
In a 2 tier, it's easy: select ID, DisplayName and get the values directly.
Most 3-tier examples work 1 table at a time. While groovy, not usefull in a 2 table scenario.
Table1:
- ID: unique identifier
- DisplayName: string
- Field1: string
- Field2: int
Table 2:
- ID: unique identifier
- Table1ID: unique identifier
- DisplayName: string
- Field3: string
- Field4: int
Table1 and Table2 are “linked” via Table2.Table1ID = Table1.ID
So Table 1 has many Table 2. Here's a typical select case to display Table 2 information
SELECT
Table2.ID,
Table2.DisplayName,
Table1.ID as Table1ID,
Table1.DisplayName as Table1DisplayName,
Field3,
Field4
FROM
Table2 INNER JOIN Table1 on Table2.Table1ID = Table1.ID
The list view would be something like this:
| Name |
Parent |
Field3 |
Field4 |
| book 1 |
author 1 |
foo |
123 |
| book 2 |
author 1 |
bar |
234 |
Name: it would be an hyperlink to Table2.aspx?Table2ID=xxx
Parent: it would be an hyperlink to Table1.aspx?Table1ID=yyy
This is extremely easy in 2 tier. 1 Select Statement that has all the info.
How do you set it up in 3 tier?
I suppose: 2 classes: Table1 and Table2.
Table1: ID Guid, DisplayName string, Field1 string, Field2 int
Table2: ID Guid, Table1 Table1, DisplayName string, Field3 string, Field4 int
So, in code, I can have Console.WriteLine(myTable2.Table1.DisplayName);
or in the table example above:
link.NavigateUrl = “Table1.aspx?Table1ID=” + myTable2.Table1.ID;
link.Text = myTable2.Table1.DisplayName;
I then suppose that when I “fill” the values for Table2, I need to fill values for Table1. But, let's say that there are many hierachies, when do I stop?
How do you fill the values?
from the Web Page:
private void GetValues(Guid table1ID)
{
Table1 t = new Table1();
t.GetValues(table1ID);
lblID.Text = t.ID.ToString(“D“);
txtDisplayName.Text = t.DisplayName;
txtField1.Text = t.Field1;
txtField2.Text = t.Field2.ToString();
}
right?
On the save, it would be quite the same, but:
private void SaveValues()
{
Guid g = new Guid(lblID.Text);
Table1 t = new Table1();
t.ID = g;
...
t.Save();
}
But, for Table2, we have a link to Table1. When and who takes care of “filling” it up? The data tier or the presentation?
If we leave it to the Presentation, then, Table2 need to save the Guid of Table1 not the pointer. So, we change Table2's pointer to Table1 to a simple Guid.
table 2 now becomes:
Table2: ID Guid, Table2 Guid, DisplayName string, Field3 string, Field4 int
This requires 2 calls to the database. One for the Table2, and one for the parent's Table1. If table2 has “links” to more than Table1, it's one call for each.
If we leave it to the DataTier, we could have Table2 return the recordset for Table2, append the recordset for Table1. Build the values for Table2, move to the next recordset and then build the values for Table1. But we have the same problem as above, when do we stop? if Table3 has a link to Table2 to Table1. Do we fill everything up at the first call? not very scalable.
Do we keep an internal copy of either the ID of the parent table and/or the pointer?
An idea would be to have Table2 return values for Table2 plus the ID/DisplayName for Table1. In Table1, there would be a special state where the data wouldn't be complete: ie only the ID and the display would be there, and it would be up to the client to get the rest (or have it automatically done) when the client tries to access the values (via properties). Something like:
public string Field1
{
get:
{
if(internalState!=Complete) GetAllData();
}
}
This way, Table2 doesn't have to “get” all the sub info, the presentation has enough for displaying, and Table1 has enough info to get the rest if need be.
Lastly, an idea would be to have the class Table2 have the data necessary:
Table2: ID Guid, Table2ID Guid, Table2DisplayName string, DisplayName string, Field3 string, Field4 int
Am I way off the track? Have I smoked crack or something?
Looking forward to your design patterns.