Para cargar datos de la base de datos a un informe RDLC tenemos que añadir un elemento DataSet. Es importante destacar que es posible cargar múltiples DataSets a un mismo informe, pero en general no suele ser algo necesario.
Generando el DataSet y TableAdapters
Lo primero que hay que hacer es ir a nuestro proyecto ReportingModule y añadir una carpeta «Data» que nos sirva para contener los DataSets de nuestros reportes. Clic derecho sobre la carpeta > Añadir > Nuevo elemento y buscamos «DataSet» (Conjunto de datos si lo tenéis en español).

Por lo general estaremos trabajando con un DataSet que tendrá múltiples TableAdapters. Si alguna vez habéis utilizado ADO.NET, estos conceptos os sonarán. Para añadir un TableAdapter, vamos a nuestro recién creado DataSet y le damos botón derecho sobre el fondo blanco y seleccionamos Añadir > TableAdapter.

En este punto, el TableAdapter os mostrará un Wizard para ayudaros a generar la consulta que necesitáis. Lo primero será añadir una conexión a vuestra base de datos dando clic a «New Connection» y seleccionando el tipo que base de datos que utilizaréis.

Le dais a «Continue» y os salta una nueva ventana para añadir la conexión. Añadís la información necesaria para generar la conexión y probáis que la conexión sea correcta utilizando el botón «Test Connection». Si estás probando en local y usas MSSQL, lo más seguro es que en «Server name» tengas que poner algo de tipo:
(localdb)\MSSQLLocalDB
Que es el nombre por defecto del servidor local. Si el servidor es correcto y los datos de inicio de sesión son adecuados (Windows Authentication para localhost va bien), en el desplegable de selección de la base de datos a utilizar debería cargar automáticamente un listado de posibles bases de datos.
Si todo es correcto, le das a aceptar y continuas para poder generar la consulta SQL o utilizar algún Stored Procedure de tu base de datos.

Los métodos podéis mantener los que vienen por defecto y os creará un objeto en el DataSet. Esta es una breve explicación de cómo usar cada uno de ellos. Cabe destacar que el resultado del wizard me ha creado un objeto de tipo DataTable al que he dejado de nombre DataTable1 (importante para entender el ejemplo).
Fill a DataTable
Sirve para rellenar un objeto de tipo DataTable preexistente con el contenido proveniente de la consulta.
// DataSet que usamos en nuestro informe RDLC
Report1DataSet reportDataSet = new Report1DataSet();
// Adaptador de tipo DataTable1 que contiene la sentencia que acabamos de crear
DataTable1TableAdapter adapter = new DataTable1TableAdapter();
// El adaptador "injecta" los datos en el DataTable1 del reporte directamente
adapter.Fill(reportDataSet.DataTable1);
// Instanciamos el informe
LocalReport informe = new LocalReport();
informe.ReportPath = "-- inserta la ruta del RDLC --";
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataSetCursos";
reportDataSource.Value = reportDataSet.DataTable1;
// Procedemos a cargar datos al informe RDLC
informe.DataSources.Add(reportDataSource);
Return a DataTable
Genera un método que devuelve un DataTable relleno con los datos indicados.
// Generamos el adaptador
DataTable1TableAdapter adapter = new DataTable1TableAdapter();
// Obtenemos los datos mediante la función
DataTable dataTableIntermedio = adapter.GetData();
// Instanciamos el informe
LocalReport informe = new LocalReport();
informe.ReportPath = "-- inserta la ruta del RDLC --";
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataSetCursos";
reportDataSource.Value = dataTableIntermedio;
// Procedemos a cargar datos al informe RDLC
informe.DataSources.Add(reportDataSource);
¿La diferencia? Poca, realmente. De hecho, si tienes un repositorio, también puedes cargar los datos haciendo uso de una lista de objetos que tengas.
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataSetCursos";
// El método puede devolver un tipo List<Curso> y también te lo acepta
reportDataSource.Value = _repositorioCurso.ObtenerTodos();
informe.DataSources.Add(reportDataSource);
La parte buena del sistema con datatables es evitar la necesidad de crear DTOs u objectos intermedios, pero si ya tienes los objetos creados para otras zonas de tu proyecto, entonces puedes aprovechar y reutilizar tus repositorios sin tener que pasar por construir datatables.
Así que usa el método que consideres más cómodo para tu proyecto o mézclalos si lo ves conveniente.
Cargar los datos al informe RDLC
Pese a que lo he adelantado ligeramente con el ejemplo anterior, en este punto necesitamos conectar una instancia de nuestro RDLC con una instancia de nuestros datos. Para usar los datos dentro de nuestro diseño, nuestro informe tiene que «saber» qué datos va a recibir y con qué esquema ha de esperarlos.
Es ahora cuando nos va a ser de utilidad el panel «Report Data» del que hablabamos en el artículo «Consideraciones a tener en cuenta al crear un informe RDLC«. En el panel le damos botón derecho a «DataSets» > «Add DataSet» y nos mostrará una ventana de selección.

En la columna de «Fields» vemos el esquema de datos que va a esperar recibir nuestro informe.
¿Recordáis que en el ejemplo anterior creamos un objeto «ReportDataSource» y le asignamos un nombre y un valor? Esta parte es muy importante, pues el nombre asignado en el código debe coincidir con el nombre elegido para nuestro DataSet.
En mi caso es «DataSetCursos» como podeis comprobar en la imagen y en el código de ejemplo del apartado anterior. Si los nombres no encajan, entonces el informe no podrá bindear los datos adecuadamente.
Ahora, con nuestro nuevo dataset creado, podemos añadir componentes del panel Toolbox dentro de nuestro reporte y bindearlos automáticamente a cualquiera de las propiedades de nuestro DataSetCursos.

Añadimos un objeto tipo tabla, damos botón derecho sobre el mismo y vamos a «Properties» para asignar nuestro dataset como fuente de datos de esa tabla.

Y ahora podemos hacer uso directo de esos datos dentro de nuestra tabla, de manera que las filas se generarán automáticamente dependiendo de cuantos datos nos devuelva la consulta del DataSetCursos.

Con la configuración indicada y haciendo una configuración mínima de un controlador MVC, el resultado obtenido sería algo tal que así:

Y con esto ya sabrías cargar datos a un informe RDLC desde las tablas de tu base de datos o usando listas de objetos derivados de tu capa de Dominio.