Laden...

ReportViewer mit Daten füllen

Letzter Beitrag vor 17 Jahren 10 Posts 6.743 Views
ReportViewer mit Daten füllen

Hallo,

Theoretisch steht in einem Reporting-Services-Report (*.rdlc) ja nicht nur das Layout des Reports, sondern da stehen ja eben halt auch alle Informationen drin, wie die Daten geladen werden sollen. Gibt es irgendein Steuerelemnt oder einen Wrapper für den ReportViewer, o.ä., der/das einen Report nicht nur Laden kann kann, sondern ihn auch mit seinen Daten verbindet

Schon mal Danke im vorraus

Die Verbindung einer RDLC zur Datenquelle steht da nur noch drin, weil es eine
Übernahme aus dem ReportingService ist, und damit der Designer die Verbindung
halten kann.

Eigentlich bist Du ganz alleine dafür zuständig, die Selects durchzuführen und die
entsehenden Datenauflistungen an den Report zu liefern.

Da das aber "nur" XML ist, kannst Du Dir die Selects, und Datenquellen ja selber
rausholen und dann binden.

Ich weiss, dass ich das kann, ich hatte aber gehofft, dass es schon was vorhandenes gibt, was genau das macht, weil das nun mal eine absolut logische Aufgabe ist, die sich aus dem Design der ReportDefinitionLanguage ergibt. Das ist sowas von der Kategorie "Hätte der Logik nach im Framework enthalten sein müssen". Warum in aller Welt lädt der ReportViewer nicht einfach die Daten? Ist das ein Versionsproblem? Kann das vielleicht erst die nächste Version?

Hallo Onlinegurke, (Nomen est Omen ?)

wenn Du den Bericht auf dem Reporting Services Server ausführst, wird die eingebaute Abfrage benutzt.

Wenn Du den Bericht lokal ausführst dann kannst Du ihn an eigene Abfragen und Quellen binden.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

Das mit dem Namen hat ne andere, eigene Geschichte

Das Problem ist, so wie ich das sehe ist die ReportDefinitionLanguage auch für andere Datenbanksysteme als auschließlich für den MS SQL Server gedacht zu sein, jedenfalls würd ich vermuten, dass in der Zeile

<DataProvider>SQL</DataProvider>

auch was anderes stehen könnte, z.B.,

<DataProvider>Oracle</DataProvider>

dann ist der ConnectionString aber eben halt auch anders. Und wenn ich meinem SQL Server sage, er soll mir mal den Bericht öffnen wird wahrscheinlich wenig bei rauskommen. Was ich suche, ist eine Möglichkeit den Bericht lokal auszuführen und dabei die im Bericht definierten Abfragen zu verwenden

//edit: In der MSDN-Doku ist auch ausdrücklich erwähnt, dass man einen SQL Server 2005-Instanz verwenden muss

Nein, es ist nicht selbstverständlich, das das ins FW gehört.

Der ReportViewer wurde geschaffen, nachdem ein Haufen von Entwicklern
eine locale Version des ReportService gefordert hatten, und MS sich dann
entschieden hat, diese Version komplett von Datenbanken zu trennen.

Und die Online Referenz zeigt in 99% aller fälle auf den ReportingService,
der Läuft halt nur mit dem SqlServer.

Der ReportViewer wurde geschaffen, nachdem ein Haufen von Entwicklern
eine locale Version des ReportService gefordert hatten, und MS sich dann
entschieden hat, diese Version komplett von Datenbanken zu trennen.

Hm, nagut, dann ist klar, warum Microsoft das nicht implementiert hat, aber es ist nunmal so, dass man durch dieses Feature die Reporting Services auch in Verbindung mit anderen Datenbanken verwenden könnte (lokal). Das Design des ReportViewers lässt das auf jeden Fall zu, deswegen hab ich mich gewundert, warum das nicht geht. Es ist mir klar, dass MS diese Lücke dann offen lässt, aber es hätte ja sein können, dass andere mittlerweile diese Lücke geschlossen haben.

Es gibt garnicht so viele Lösungen zum Reportviewer.

Du hast aber sicher schon alle Demos auf www.gotreportviewer.com durchgesehen?

nein, die Seite kannt ich nicht. Danke für den Link.

Machs jetzt selber:
(Der Code ist orginal in VB.NET geschrieben, aber SharpDevelop hat's freundlicherweise übersettzt 🙂 )

using Microsoft.Reporting.WinForms;
using Microsoft.Reporting;
using System.Xml;
public class ReportManager : System.ComponentModel.Component
{

	public void Load(string ReportPath)
	{
		Viewer.LocalReport.ReportPath = ReportPath;

		IO.FileStream fs = new IO.FileStream(ReportPath, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read);
		XmlReader xr = XmlReader.Create(fs);
		Dictionary<string, IDbConnection> conns = this.ReadConnections(xr);
		Dictionary<string, DataTable> tables = this.ReadQuerys(xr, conns);
		foreach (IDbConnection conn in conns.Values) {
			conn.Close();
			conn.Dispose();
		}
		xr.Close();
		fs.Dispose();

		foreach (KeyValuePair<string, DataTable> kv in tables) {
			Viewer.LocalReport.DataSources.Add(new ReportDataSource(kv.Key, kv.Value));
		}

		Viewer.RefreshReport();
	}

	public ReportManager()
	{
		conn_creates = new Dictionary<string, Creator<IDbConnection>>();
		conn_creates.Add("SQL", SQLKonstruktor);
	}

	private ReportViewer _viewer;
	private Dictionary<string, Creator<IDbConnection>> conn_creates;

	public ReportViewer Viewer {
		get { return _viewer; }
		set { _viewer = value; }
	}

	public Creator<IDbConnection> ConnectionCreator {
		get {
			if (conn_creates.ContainsKey(ProviderName))
			{
				return conn_creates(ProviderName);
			}
			else
			{
				return null;
			}
		}
		set {
			if (conn_creates.ContainsKey(ProviderName))
			{
				conn_creates(ProviderName) = value;
			}
			else
			{
				conn_creates.Add(ProviderName, value);
			}
		}
	}

	private Dictionary<string, IDbConnection> ReadConnections(XmlReader xr)
	{
		Dictionary<string, IDbConnection> functionReturnValue = null;
		functionReturnValue = new Dictionary<string, IDbConnection>();
		if (xr.ReadToFollowing("DataSources"))
		{
			while (xr.Read) {
				if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSources") break; // TODO: might not be correct. Was : Exit While
 
				((IDictionary<string, IDbConnection>)functionReturnValue).Add(ReadConnection(xr));
			}
		}
		return functionReturnValue;
		return functionReturnValue;
	}

	private KeyValuePair<string, IDbConnection> ReadConnection(XmlReader xr)
	{
		xr.ReadStartElement("DataSource");
		string key = xr.GetAttribute("Name");
		string prov = string.Empty;
		string connstr = string.Empty;
		while (xr.Read) {
			if (xr.NodeType == XmlNodeType.Element)
			{
				if (xr.Name == "ConnectionString")
				{
					connstr = xr.ReadElementString;
				}
else if (xr.Name == "DataProvider") {
					prov = xr.ReadElementString;
				}
			}
			if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSource")
			{
				if (this.conn_creates.ContainsKey(prov))
				{
					IDbConnection conn = this.conn_creates(prov).Invoke;
					conn.ConnectionString = connstr;
					return new KeyValuePair<string, IDbConnection>(key, conn);
				}
				else
				{
					return new KeyValuePair<string, IDbConnection>(key, null);
				}
			}
		}
		return null;
	}

	private Dictionary<string, DataTable> ReadQuerys(XmlReader xr, Dictionary<string, IDbConnection> Conns)
	{
		Dictionary<string, DataTable> functionReturnValue = null;
		functionReturnValue = new Dictionary<string, DataTable>();
		if (xr.ReadToFollowing("DataSets"))
		{
			while (xr.Read) {
				if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSets") break; // TODO: might not be correct. Was : Exit While
 
				((IDictionary<string, DataTable>)functionReturnValue).Add(ReadQuery(xr, Conns));
			}
		}
		return functionReturnValue;
		return functionReturnValue;
	}

	private KeyValuePair<string, DataTable> ReadQuery(XmlReader xr, Dictionary<string, IDbConnection> Conns)
	{
		xr.ReadStartElement("DataSet");
		string key = xr.GetAttribute("Name");
		xr.ReadStartElement("Query");
		string cmd = string.Empty;
		string ds = string.Empty;
		while (xr.Read) {
			if (xr.NodeType == XmlNodeType.Element)
			{
				if (xr.Name == "CommandText")
				{
					cmd = xr.ReadElementString;
				}
else if (xr.Name == "DataSourceName") {
					ds = xr.ReadElementString;
				}
			}
			if (xr.NodeType == XmlNodeType.EndElement && xr.Name == "DataSet")
			{
				if (Conns.ContainsKey(ds))
				{
					return new KeyValuePair<string, DataTable>(key, GetDataTable(Conns(ds), cmd));
				}
				else
				{
					return new KeyValuePair<string, DataTable>(key, new DataTable());
				}
			}
		}
		return null;
	}

	private DataTable GetDataTable(IDbConnection Connection, string Command)
	{
		DataTable functionReturnValue = null;
		functionReturnValue = new DataTable();
		IDbCommand cmd = null;
		try {
			if (!(Connection.State == ConnectionState.Open)) Connection.Open(); 
			cmd = Connection.CreateCommand;
			cmd.CommandText = Command;
			using (IDataReader dr = cmd.ExecuteReader) {
				functionReturnValue.Load(dr);
			}
			cmd.Dispose();
		}
		catch (Exception ex) {
			if ((cmd != null)) cmd.Dispose(); 
		}
		return functionReturnValue;
	}

	private IDbConnection SQLKonstruktor()
	{
		return new Data.SqlClient.SqlConnection();
	}
}

Achso, Creator<T> ist ein Delegate, dass eine Instanz vom Typ T zurückgibt...