我有一个代表清单信息的数据库。 公司A收到发票并将其拆分为公司A,B,C。
我们需要为每个收到的发票创建一个清单文件。
我创建的数据库具有以下规格:
这是db的剥离表示:
+-----------------+ +------------------+ +--------------------+
| DOCUMENTS + | ROWS | | COLS |
+-----------------+ +------------------+ +--------------------+
| DocID PK |1-*| DocID PK |1-*| DocID PK | +-----------------+
| ... | | Row PK |1-*| Row PK | | COMPANIES |
+-----------------+ | Description | | Col PK | +-----------------+
| RebillAmount | | CompanyID |*-1| CompanyID PK |
+------------------+ | RebilledAmount | | Description |
+--------------------+ +-----------------+
我想要实现的是网格表示,如下所示:
+-----------------+--------------+-------------+-------------+-------------+
| Description | RebillAmount | "Company A" | "Company B" | "Company C" | ...
+-----------------+--------------+-------------+-------------+-------------+
| ISP invoice | € 1.000,00 | € 333,00 | € 333,00 | € 334,00 |
| Insurance | € 600,00 | € 0,00 | € 400,00 | € 200,00 |
| ... | | | | |
+-----------------+--------------+-------------+-------------+-------------+
使用Linq to SQL检索数据。
我通过手动遍历行和列并使用字典来跟踪列来成功创建了DataGridView:
Dim CompanyCols as new Dictionary(Of Integer, DataGridViewColumn)
Dim DocID = 1
Dim Doc = (From d In dc.Documents Where f.DocID = DocID Select d).Single
For Each r In Doc.Rows
Dim rowid = Grid.Rows.Add()
Dim row = Grid.Rows(rowid)
row.Cells(ColEnum.Description).Value = r.Description
riga.Cells(ColEnum.RebillAmount).Value = r.RebillAmount
Dim col As DataGridViewColumn
For Each c In r.Cols
If CompanyCols.ContainsKey(c.CompanyID) Then
col = CompanyCols(c.CompanyID)
Else
Dim newcol = New DataGridViewTextBoxColumn With {.HeaderText = c.Companies.Description}
col = Grid.Columns(Grid.Columns.Add(newcol))
CompanyCols.Add(c.CompanyID, col)
End If
row.Cells(col.Index).Value = c.RebillAmount
Next
Next
不幸的是,这种方法断开了与数据库对象的链接,因此,如果我需要编辑数据并保存它们,则必须扫描整个网格并手动更新“ Doc”对象及其子对象。
是否可以将行“绑定”到Doc.rows和将列“绑定”到Doc.cols?
谢谢!
答案 0 :(得分:0)
因此,您有一系列文档。您要在表中显示一个文档。表中的列代表文档中提到的Companies
。不同的文件可能具有不同的公司数量。
幸运的是,您只希望在表格中仅显示一个文档:获得文档后,您知道应该将哪些公司作为列添加到表格中。
尽管您定义了一个文档中的每一行具有相同数量的列,因此,每个文档都使用相同数量的公司,但您并未指定每行使用相同的公司
所以您最终可能会这样:
Rows[0] has two Cols:
Cols[0] has Company[0]
Cols[1] has Company[1]
Rows[1] has two Cols:
Cols[0] has Company[0]
Cols[1] has Company[2]
Rows[3] has two Cols:
Cols[0] has Company[3]
Cols[1] has Company[4]
如果我查看您的代码,在这种情况下,您希望显示5列。
Row Company[0] Company[1] Company[2] Company[3] Company[4]
----------------------------------------------------------------------------
Row[0] aaa bbb
Row[1] ccc ddd
Row[2] eee fff
表中的每个公司列都有一个列标题,用于显示公司名称。如果您有一行,则如果该行未使用公司,则该行的单元格的值将为null,或者使用使用其名称显示在列标题中的公司的单元格的RebilledAmount
。
这意味着一旦您获取了文档,就需要了解所有使用过的公司。每个公司成为一个专栏。在每列中,您都需要记住公司名称和公司ID
对于要添加的每一行,您必须找出与该行的列所使用的公司的ID相匹配的列。
我的视觉基础有点生锈,所以我将向您展示C#中的代码。我敢肯定,您将能够掌握该想法并将其转换为视觉基础
Document fetchedDocument = ...
// find out which companies are used by the Document.
// from every company remember the name and the Id:
var companyInfo = fetchedDocument.Rows // take all rows
.SelectMany(row => row.Cols) // from these rows take all Cols
.Select(col => new
{
CompanyId = col.CompanyId, // from every Col take the CompanyId
Name = col.Company.Name, // and the company name
})
.Distinct(); // remove duplicates
如果在获取文档时未获取公司名称,则必须在单独的查询中获取它们。如果您在本地某处有公司名称,则可以在“词典”中或之后通过以下方式获取它们:
var companyIds = fetchedDocument.Rows // take all rows
.SelectMany(row => row.Cols) // from all rows take the Cols
.Select(col => col.CompanyId) // from every col take the companyId
.Distinct(); // remove duplicates
// add the CompanyNames
var companyInfo = companyIds.Select(companyId => new
{
Id = companyId,
Name = CompanyCollection[companyId].CompanyName,
});
一旦您知道所有公司,便可以添加所有列。我们将首先添加Description
和RebillAmount
的列:
myDataGridView.Columns.Clear();
// Column Description:
int columnDescriptionIndex = myDataGridView.Columns.Add(new DataGridViewColumn()
{
Name = "ColDescription", // name of the column
HeaderText = "Description", // header text
ValueType = typeof(string), // this column shows strings
DataPropertyName = "Description", // this column shows property Description
});
// Column RebillAmount:
int columnRebillAmountIndex = myDataGridView.Columns.Add(new DataGridViewColumn()
{
Name = "ColRebillAmount", // name of the column
HeaderText = "RebillAmount", // header text
DataPropertyName = "RebillAmount", // this column shows property RebillAmount
ValueType = typeof(decimal), // this column shows decimals
// if desired: add a DefaultCellStyle to define the display format of the amount
}
现在添加公司列。在每个公司列中,您都需要记住所显示公司的ID。为此,我们创建一个DataGridViewColumn的子类,其中包含所显示公司的ID:
class CompanyColumn : DataGridViewColumn
{
public int CompanyId {get; private set;}
public CompanyColumn(int companyId, string companyName)
{
this.CompanyId = companyId;
Name = companyName; // name of the column
HeaderText = companyName; // header text
ValueType = typeof(decimal); // this column shows decimals
// if desired: add a DefaultCellStyle to define the display format
}
}
每个二手公司增加一栏;为了快速查找:将列索引放在Dictionary中, 键为companyId,值为columnIndex
var companyColumns = new Dictionary<int, int>()
foreach(var usedCompany in usedCompanies)
{
var columnIndex = myDataGridView.Columns
.Add(new CompanyColumn(usedCompany.Id, usedCompany.Name);
companyColumns.Add(usedCompany.Id, columnIndex);
}
添加所有列之后,可以添加行:
myDataGridView.Rows.Clear();
foreach(var row in document.Rows)
{
var addedRow = myDataGridView.AddRow();
// Description and RebillAmount
addedRow.Cells[colDescriptionIndex].Value = row.Description;
addedRow.Cells[colRebillAmountIndex].Value = row.RebillAmount;
// add the value for every company in the row, in the correct column
foreach (var col in row.Cols
{
// every col has a companyId
// find in the dictionary the index of the column that represents this company
int columnIndex = companyColumns[col.CompanyId];
// put the RebilledAmount in the column with the found index
addedRow.Cells[columnIndex].Value = cell.RebilledAmount;
}
}
现在,如果更改了单元格,则要更改“文档”中的相应值:
void UpdateChangedCell(DataGridViewCell cell)
{
if (cell.ColumnIndex == colDescriptionIndex)
{ // the changed cell is a description cell
string description = (string)cell.Value;
document.Rows[cell.RowIndex].Description = description;
}
else if (cell.ColumnIndex == colRebillAmountIndex)
{ // the changed cell is a rebillAmount cell
decimal rebillAmount = (decimal)cell.Value;
document.Rows[cell.RowIndex].RebillAmount = rebillAmount;
}
else
{ // the changed cell is in one of the company columns:
CompanyColumn column = (CompanyColumn)myDataGridView.Columns[cell.ColumnIndex];
int companyId = column.CompanyId;
decimal rebilledAmount = (decimal)column.Value;
// update the one and only Col in this Row that has CompanyId
var colToUpdate = row.Cols
.Where(col => col.CompanyId == companyId)
.Single();
colToUpdate.RebilledAmount = rebilledAmount;
}
}