Domanda

A rischio di essere sottomesso, voglio chiedere quale sia il meccanismo migliore (il migliore è ovviamente soggettivo per la violazione pratica inerente qui) per visualizzare i dati da una tabella, usando C #, con un lotto di colonne. Intendo qualcosa come 1000.

Ora, prima di essere tutti contenti, o di dare risposte come " perché diavolo dovresti mai avere una tabella con tante colonne " lasciami dire che in realtà fa parte di un requisito di progettazione. Stiamo raccogliendo dati il ??più velocemente possibile da 1000 punti dati. Dobbiamo memorizzarli il più velocemente possibile, quindi il tavolo piatto. I dati devono essere direttamente accessibili da SQL Server, quindi dal database (stiamo usando SQL Compact con table-direct).

Quindi dimentichiamo, per ora, tutto ciò che abbiamo imparato sulla corretta progettazione del database, le regole di normalizzazione, ecc. e concentriamoci solo sul fatto che ho una tabella con 1000 colonne e voglio essere in grado di visualizzare i dati sullo schermo per verificare che i dati siano effettivamente presenti lì.

Ho provato una griglia di dati. Vomita perché (non a caso) non è progettato per gestire così tante colonne.

Ho provato a utilizzare il visualizzatore in Studio. Si verifica dopo 256, inoltre l'utente finale non avrà Studio installato comunque.

Per ora il risultato non deve essere carino, non deve essere aggiornabile, né deve essere sensibile alle modifiche dei dati - solo un'istantanea statica dei dati nella tabella in un determinato momento.

Informazioni rilevanti (o semi-pertinenti):

  • La tabella ha 1000 colonne (leggi sopra prima di fare clic felice)
  • Utilizzo di SQL Compact versione 3.5
  • In esecuzione sul desktop
  • Alla ricerca di una risposta con codice gestito
È stato utile?

Soluzione 3

Ok, quella che si è rivelata la risposta giusta per me è stata usare la controllo ReportViewer , ma non documentato in alcun modo in MSDN. Il problema è che ho dati dinamici, quindi ho bisogno di un rapporto dinamico e tutti i tutorial, ecc. Sembrano supporre che tu abbia il lusso di sapere tutto in fase di progettazione in modo che tu possa puntare e fare clic su una procedura guidata.

La soluzione ha richiesto un paio di pezzi. Innanzitutto, ho dovuto creare un codice per generare dinamicamente il RDLC che ReportViewer utilizza per descrivere il layout del report e quali campi di dati mappano a cosa. Questo è quello che mi è venuto in mente:

public static Stream BuildRDLCStream(
    DataSet data, string name, string reportXslPath)
{
  using (MemoryStream schemaStream = new MemoryStream())
  {
    // save the schema to a stream
    data.WriteXmlSchema(schemaStream);
    schemaStream.Seek(0, SeekOrigin.Begin);

    // load it into a Document and set the Name variable
    XmlDocument xmlDomSchema = new XmlDocument();
    xmlDomSchema.Load(schemaStream);        
    xmlDomSchema.DocumentElement.SetAttribute("Name", data.DataSetName);

    // load the report's XSL file (that's the magic)
    XslCompiledTransform xform = new XslCompiledTransform();
    xform.Load(reportXslPath);

    // do the transform
    MemoryStream rdlcStream = new MemoryStream();
    XmlWriter writer = XmlWriter.Create(rdlcStream);
    xform.Transform(xmlDomSchema, writer);
    writer.Close();
    rdlcStream.Seek(0, SeekOrigin.Begin);

    // send back the RDLC
    return rdlcStream;
  }
}

Il secondo pezzo è un file XSL che ho estratto da Blog di Dan Shipe . Il codice RDLC era piuttosto inutile in quanto era tutto destinato all'uso Web, ma l'XSL è oro puro. L'ho messo in fondo a questo post per completezza nel caso in cui quel blog non sia mai offline.

Una volta che ho quei due pezzi, era semplicemente una questione di creare un modulo con un controllo ReportViewer su di esso, quindi usare questo bit di codice per configurarlo:

ds.DataSetName = name;

Stream rdlc = RdlcEngine.BuildRDLCStream(
    ds, name, "c:\\temp\\rdlc\\report.xsl");

reportView.LocalReport.LoadReportDefinition(rdlc);
reportView.LocalReport.DataSources.Clear();
reportView.LocalReport.DataSources.Add(
    new ReportDataSource(ds.DataSetName, ds.Tables[0]));
reportView.RefreshReport();

La chiave qui è che 'ds' è un oggetto DataSet con al suo interno una singola DataTable con i dati da visualizzare.

Ancora una volta, per completezza, ecco l'XSL - scusa per le dimensioni:

    <?xml version="1.0"?>
    <!-- Stylesheet for creating ReportViewer RDLC documents -->
    <xsl:stylesheet version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:msxsl="urn:schemas-microsoft-com:xslt"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
      xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner"  xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition"
      >

     <xsl:variable name="mvarName" select="/xs:schema/@Name"/>
     <xsl:variable name="mvarFontSize">8pt</xsl:variable>
     <xsl:variable name="mvarFontWeight">500</xsl:variable>
     <xsl:variable name="mvarFontWeightBold">700</xsl:variable>


     <xsl:template match="/">
      <xsl:apply-templates select="/xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence">
      </xsl:apply-templates>
     </xsl:template>

     <xsl:template match="xs:sequence">
      <Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition">
       <BottomMargin>1in</BottomMargin>
       <RightMargin>1in</RightMargin>
       <LeftMargin>1in</LeftMargin>
       <TopMargin>1in</TopMargin>
       <InteractiveHeight>11in</InteractiveHeight>
       <InteractiveWidth>8.5in</InteractiveWidth>
       <Width>6.5in</Width>
       <Language>en-US</Language>
       <rd:DrawGrid>true</rd:DrawGrid>
       <rd:SnapToGrid>true</rd:SnapToGrid>
       <rd:ReportID>7358b654-3ca3-44a0-8677-efe0a55c7c45</rd:ReportID>

       <xsl:call-template name="BuildDataSource">
       </xsl:call-template>

       <xsl:call-template name="BuildDataSet">
       </xsl:call-template>

       <Body>
        <Height>0.50in</Height>
        <ReportItems>
         <Table Name="table1">
          <DataSetName><xsl:value-of select="$mvarName" /></DataSetName>
          <Top>0.5in</Top>
          <Height>0.50in</Height>
          <Header>
           <TableRows>
            <TableRow>
             <Height>0.25in</Height>
             <TableCells>

              <xsl:apply-templates select="xs:element" mode="HeaderTableCell">
              </xsl:apply-templates>

             </TableCells>
            </TableRow>
           </TableRows>
          </Header>
          <Details>
           <TableRows>
            <TableRow>
             <Height>0.25in</Height>
             <TableCells>

              <xsl:apply-templates select="xs:element" mode="DetailTableCell">
              </xsl:apply-templates>

             </TableCells>
            </TableRow>
           </TableRows>
          </Details>
          <TableColumns>

           <xsl:apply-templates select="xs:element" mode="TableColumn">
           </xsl:apply-templates>

          </TableColumns>
         </Table>
        </ReportItems>
       </Body>
      </Report>
     </xsl:template>

     <xsl:template name="BuildDataSource">
      <DataSources>
       <DataSource Name="DummyDataSource">
        <ConnectionProperties>
         <ConnectString/>
         <DataProvider>SQL</DataProvider>
        </ConnectionProperties>
        <rd:DataSourceID>84635ff8-d177-4a25-9aa5-5a921652c79c</rd:DataSourceID>
       </DataSource>
      </DataSources>
     </xsl:template>

     <xsl:template name="BuildDataSet">
      <DataSets>
       <DataSet Name="{$mvarName}">
        <Query>
         <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
         <CommandText/>
         <DataSourceName>DummyDataSource</DataSourceName>
        </Query>
        <Fields>

         <xsl:apply-templates select="xs:element" mode="Field">
         </xsl:apply-templates>

        </Fields>
       </DataSet>
      </DataSets>
     </xsl:template>

     <xsl:template match="xs:element" mode="Field">
      <xsl:variable name="varFieldName"> 
       <xsl:value-of select="@name" />
      </xsl:variable>

      <xsl:variable name="varDataType">
       <xsl:choose>
        <xsl:when test="@type='xs:int'">System.Int32</xsl:when>
        <xsl:when test="@type='xs:string'">System.String</xsl:when>
        <xsl:when test="@type='xs:dateTime'">System.DateTime</xsl:when>
        <xsl:when test="@type='xs:boolean'">System.Boolean</xsl:when>
       </xsl:choose>
      </xsl:variable>

      <Field Name="{$varFieldName}">
       <rd:TypeName><xsl:value-of select="$varDataType"/></rd:TypeName>
       <DataField><xsl:value-of select="$varFieldName"/></DataField>
      </Field>
     </xsl:template>

     <xsl:template match="xs:element" mode="HeaderTableCell">
      <xsl:variable name="varFieldName"> 
       <xsl:value-of select="@name" />
      </xsl:variable>

      <TableCell>
       <ReportItems>
        <Textbox Name="textbox{position()}">
         <rd:DefaultName>textbox<xsl:value-of select="position()"/>
         </rd:DefaultName>
         <Value><xsl:value-of select="$varFieldName"/></Value>
         <CanGrow>true</CanGrow>
         <ZIndex>7</ZIndex>
         <Style>
          <TextAlign>Center</TextAlign>
          <PaddingLeft>2pt</PaddingLeft>
          <PaddingBottom>2pt</PaddingBottom>
          <PaddingRight>2pt</PaddingRight>
          <PaddingTop>2pt</PaddingTop>
          <FontSize><xsl:value-of select="$mvarFontSize"/></FontSize> 
          <FontWeight><xsl:value-of select="$mvarFontWeightBold"/></FontWeight> 
          <BackgroundColor>#000000</BackgroundColor> 
          <Color>#ffffff</Color>
          <BorderColor>
           <Default>#ffffff</Default>
          </BorderColor>
          <BorderStyle>
           <Default>Solid</Default>
          </BorderStyle>
         </Style>
        </Textbox>
       </ReportItems>
      </TableCell>
     </xsl:template>

     <xsl:template match="xs:element" mode="DetailTableCell">
      <xsl:variable name="varFieldName"> 
       <xsl:value-of select="@name" />
      </xsl:variable>

      <TableCell>
       <ReportItems>
        <Textbox Name="{$varFieldName}">
         <rd:DefaultName><xsl:value-of select="$varFieldName"/></rd:DefaultName>
         <Value>=Fields!<xsl:value-of select="$varFieldName"/>.Value</Value>
         <CanGrow>true</CanGrow>
         <ZIndex>7</ZIndex>
         <Style>
          <TextAlign>Left</TextAlign>
          <PaddingLeft>2pt</PaddingLeft>
          <PaddingBottom>2pt</PaddingBottom>
          <PaddingRight>2pt</PaddingRight>
          <PaddingTop>2pt</PaddingTop>
          <FontSize><xsl:value-of select="$mvarFontSize"/></FontSize> 
          <FontWeight><xsl:value-of select="$mvarFontWeight"/></FontWeight> 
          <BackgroundColor>#e0e0e0</BackgroundColor> 
          <Color>#000000</Color> 
          <BorderColor>
           <Default>#ffffff</Default> 
          </BorderColor>
          <BorderStyle>
            <Default>Solid</Default>
          </BorderStyle>
         </Style>
        </Textbox>
       </ReportItems>
      </TableCell>
     </xsl:template>

     <xsl:template match="xs:element" mode="TableColumn">
      <TableColumn>
       <Width>0.75in</Width>
      </TableColumn>
     </xsl:template>

     <xsl:template name="replace-string">
      <xsl:param name="text"/>
      <xsl:param name="from"/>
      <xsl:param name="to"/>
      <xsl:choose>
       <xsl:when test="contains($text, $from)">
        <xsl:variable name="before" select="substring-before($text, $from)"/>
        <xsl:variable name="after" select="substring-after($text, $from)"/>
        <xsl:variable name="prefix" select="concat($before, $to)"/>
        <xsl:value-of select="$before"/>
        <xsl:value-of select="$to"/>
        <xsl:call-template name="replace-string">
         <xsl:with-param name="text" select="$after"/>
         <xsl:with-param name="from" select="$from"/>
         <xsl:with-param name="to" select="$to"/>
        </xsl:call-template>
       </xsl:when>
       <xsl:otherwise>
        <xsl:value-of select="$text"/>
       </xsl:otherwise>
      </xsl:choose>
     </xsl:template>
    </xsl:stylesheet>

Altri suggerimenti

Se hai intenzione di implementare il tuo controllo utente personalizzato, potresti fare una griglia Fisheye in questo modo:

  

Link immagine morto

Questo esempio mostra un pannello 3x4 a grandezza naturale che si sposta all'interno di una tabella 9x10. Dato che (presumo) non è necessario modificare questi dati, l'interfaccia utente potrebbe essere semplicemente qualcosa in cui l'utente prende il pannello e lo trascina in giro. Se sei davvero masochista e / o hai molto tempo libero, puoi anche avere più pannelli fisheye sulla stessa griglia, permettendoti di confrontare una o più regioni della griglia contemporaneamente.

Aggiornamento: Silverlight ha uno di questi , a quanto pare. Sorta di.

È possibile formattare tutti i numeri come stringhe di n caratteri con spazi e quindi visualizzarli in un carattere a larghezza fissa.

1       2       3       4       6      36     436    6346
2       3       4       6      36     436    6346       0
3       4       6      36     436    6346       3       4
4       6      36     436    6346     333     222     334

Che dire della memorizzazione dei dati in un file CSV, che ti darebbe opzioni per la visualizzazione. Se il tuo utente ha Excel o Open Office Calc, potrebbe facilmente importare i dati (non sei sicuro che ci sia un limite di colonna su Calc, ma Excel 2007 può contenere 16384 colonne) e visualizzarlo attraverso quel programma?

devi visualizzare più righe su una singola tabella?

la mia ipotesi è che questi dati sono numerici, c'è un modo in cui puoi visualizzare i dati di una singola riga come una griglia 20 * 50 o qualcosa del genere, quindi semplicemente impaginare le righe?

Ad esempio, riga 1, colonna 1 = colonna 1 del database, riga 2, colonna 1 = colonna 21 del database, ecc.

Id = 1
     1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
----|--------------------------------------------------------
  0 |  
 20 |  
 40 |
 60 |
 80 |
100 |
120 |
etc |

prova una tabella html con un carattere molto piccolo

se sei preoccupato per la formattazione della tabella usa CSS:

td { font-size: 0.2em; text-align: right; }

in alternativa, se tutti i tuoi numeri hanno le stesse dimensioni, potresti anche generare un "muro di numeri" display, ad es. utilizzare un carattere a larghezza fissa e visualizzare colonne di 5 caratteri in un riquadro di scorrimento

Dipende un po 'da quanto deve essere carina. Se si tratta solo di uno strumento di controllo debug / spot, è possibile affiancare diversi DataGrid, ciascuno con una selezione di colonne. Sarebbe un po 'brutto, ma sarebbe praticabile.

OTOH, se hai bisogno di uno strumento semilucido, ti consigliamo di trovare un controllo personalizzato per gestirlo. Fondamentalmente, si carica la sezione del database visualizzato, con un po 'di buffer, e quando l'utente scorre i dati attualmente caricati, si esegue una nuova query.

Un DataGrid (o anche un ListView) dovrebbe essere in grado di gestire una tabella con 32 colonne e 32 righe, il che consentirebbe di visualizzare contemporaneamente l'intero valore di una riga DB. Ciò ti consentirebbe di vedere immediatamente se alcune celle mancavano o meno di dati.

Mi sento sporco anche per averlo suggerito, ma potresti fare qualcosa del tipo:

SELECT Field1 + ' - ' + Field2 + ... AS EvilMegaColumn FROM Table

ma in realtà penso che questo rientri nella categoria di " se stai incontrando questa limitazione, stai facendo qualcosa di sbagliato " ;. Non riesco davvero a vedere alcun motivo, velocità o altro per aver bisogno di 1000 colonne ...

Chi leggerà una tabella di 1000 colonne ??? Prova a pensare al modo di filtrare o visualizzare i dati.

Forse dovresti studiare un diverso tipo di database. Ho sentito che i database orientati alle colonne sono utili per questo genere di cose (mentre un tipico RDBMS è orientato alle righe). Inoltre, se non tornerai ad aggiornare le righe dopo che sono state inserite per la prima volta, forse un file flat binario sarebbe meglio di una tabella gigante?

Vorrei che questo fosse un approfondimento. Nella prima pagina (o nella parte superiore della pagina) avresti i controlli che selezionano la riga. Nella pagina successiva (o nella parte inferiore della pagina) visualizzerai i dati della riga selezionata. A seconda della larghezza della cella richiesta, è possibile farlo come ad esempio 100 righe da 10 colonne o 1000 righe da 1 colonna.

Questo sarebbe abbastanza facile da fare come javascript dinamico sul lato client: potresti persino renderlo modificabile in questo modo. Non sono sicuro di come funzionerebbe in C #.

Se stai subito dopo una verifica non puoi controllare ogni campo a livello di codice e segnalare che l'intera riga è ok !. Quindi hai bisogno di una griglia di dati molto semplice che elenca le righe non molto buone.

Possono quindi essere esaminati con qualsiasi tecnica sia possibile applicare a una singola riga in quanto non sarà necessario sfogliare i campi nella maggior parte dei casi. Sto assumendo qui che puoi già vedere l'intera riga in qualche modo e sto cercando un modo per sfogliare più righe contemporaneamente alla ricerca di dati mancanti (automatizzare questo renderà molto più affidabile).

Arrivandoci da un angolo obliquo, chiederei se l'utente deve avere tutte le colonne "caricate". contemporaneamente?

Se gli utenti sarebbero felici di visualizzare contemporaneamente un sottoinsieme di colonne (diciamo 100 alla volta o set specifici alla volta), allora utilizzerei una sorta di griglia di dati (quella incorporata in o un ListView, o forse un terzo) per visualizzare il sottoinsieme, con CheckedListView ancorato lateralmente, che consente di visualizzare il sottoinsieme di interesse.

In alternativa, potresti visualizzare alcuni tipi di dati di riepilogo che mostrano il conteggio / media / xxx per gruppi di 100 colonne?

Consiglio di indagare su qualcosa di diverso da un layout piatto. Nella mia esperienza, i database hanno restrizioni sul numero di colonne e sulla dimensione dei byte di riga.

  • Il tuo SQL può consentire la definizione di 1000 colonne.
  • Una riga SQL non può superare il limite di byte della riga.

Ogni implementazione del database ha una dimensione di pagina (4k / 8k) e una singola riga deve rientrare in questa dimensione dei dati. I NULL sono in genere omaggi. Ciò significa che 1000 pollici 1000 x 4 byte solo si adattano a dimensioni di pagina 4k.

Se stai parlando di dati con varchars, il problema è peggiore. Quanti caratteri ci sono in ogni colonna? Quante colonne possono essere compilate? Se hai in media 10 caratteri e la dimensione della tua pagina è 8k, perdi i dati con un errore SQL.

Ridi se devi, ma questa situazione si è verificata con una dattilografa particolarmente lunga in un datatario piatto che sapevo stava spingendo i limiti.

  

.. per verificare che i dati stiano effettivamente andando lì.

Può essere obsoleto, ma è possibile utilizzare la mappa di pixel in cui il singolo pixel rappresenta una singola cella della tabella (lo schermo è più di 1000) o 10 celle per un pixel con area di zoom al clic.

Il colore del pixel dipenderà dai dati. Potrebbe essere bianco / nero per vuoto / dati. Oppure potrebbe essere il colore a mostrare che il valore aumenta o diminuisce ad ogni riga. O rosso per improvvisi salti di dati. Tutte le anomalie che potresti catturare normalmente con l'occhio nella griglia dei dati.

Quindi tutto ciò che serve è catturare le coordinate dei clic nell'area di interesse e utilizzare una piccola tabella per mostrare quella parte della tabella senza alcuno scorrimento.

Basta fare clic per tornare alla mappa pixel.

Dato che l'utente dovrà comunque scorrere in orizzontale, è possibile utilizzare una griglia di dati normale che mostri un numero ragionevole di colonne (diciamo 50). Quindi hai una barra di scorrimento orizzontale posizionata sotto la griglia che seleziona un sottoinsieme di colonne da mostrare. Quando la barra di scorrimento si trova a sinistra, visualizzi le colonne 1-50, quando fai clic sulla freccia destra vai a 2-51, ecc.

Questo ti dà la possibilità di scorrere senza mai sovraccaricare un controllo della griglia con i dati. Mentre perderai la possibilità di spostarti liberamente nella tabella o fare grandi selezioni rettangolari, non sembra che questo sarebbe un problema per questa applicazione.

Quanti dati sono fondamentali per la vista iniziale? Posso vedere fare qualcosa come una griglia di tipo master / dettaglio in cui stai posizionando le colonne critiche (diciamo come 10) sul datagrid e quando l'utente fa clic per visualizzare i dettagli, puoi prendere le colonne rimanenti e visualizzarle in un " ; area delle proprietà " o qualcosa in tal senso.

Se tutto ciò di cui hai bisogno è assicurarti che i dati vengano popolati, perché non avere ogni colonna con un valore predefinito, ad esempio "void", "blank", ecc.

Quindi puoi scorrere attraverso il conteggio non predefinito / totale per mostrare una percentuale.

Ora puoi visualizzare la completezza dei dati con un valore percentuale, forse anche registrare quali colonne avevano i valori predefiniti (come un elenco / array) per ulteriori indagini.

Potresti prendere in considerazione la possibilità di verificare con la tua base di utenti e di vedere ciò che realmente hanno bisogno di vedere, quindi impostare le viste per ogni necessità distinta, al fine di ottenere il conto alla rovescia della colonna.

Un'altra opzione sarebbe quella di leggere i dati e creare un enorme set statico di pagine html da esso. Quindi è possibile richiamare il browser dall'interno del programma per visualizzarlo.

Avere un riquadro scorrevole e mostrare 10 colonne alla volta (queste possono essere attivamente caricate o memorizzate nella cache o qualsiasi altra cosa sia necessaria). Quando si scorre a sinistra, mostra i primi dieci. Mentre scorri verso destra, mostra quest'ultima sequenza di colonne. Quindi, tutto sommato, solo 10 colonne sono attive in un dato punto. Cercare di visualizzare effettivamente 1000 colonne sarebbe secondo me diverso in qualsiasi altro modo. PS: Questa non è altro che un'ipotesi ideale; Non sono davvero sicuro che sia possibile da remoto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top