I kinda like the rdlc/reportviewer reports in VS2008. It is not what you can call high tech reporting but I think it will do everything I need it to do.
But the question is do we do reporting on the domainmodel or a separate viewmodel/reportingmodel? Or do we just use datasets and custom sql?
Well, I am a guy that tends to use objects, so I like to go the object source path. And the Microsoft reports have some support for this. However the support is not as great as I have seen in other products. Now I see no reason why you would not make your reports use the database directly, after all domainmodels are all about OLTP and not OLAP.
I have not yet found a way to easily bind against list/collections. You always have to make a subreport for that, which seems a bit over the top. Perhaps we can have this in 2010.
But I would always recommend making a viewmodel for the reports you need to make, and for the following reasons:
- It will make live easier when you have to switch reporting engines (which I had to do)
- reporting data is all about strings: do the formatting in the viewmodel and give the report strings (sometimes images)
- the formatting is easier in the viewmodel than it is in most reporting engines
Let’s give you an example with rdlc as to why it is easier to use a viewmodel instead of reporting against the domainmodel.
The domainmodel looks something like this:
```vbnet Public Class Invoice Private _total As Decimal Private _customer As Customer Private _invoiceDate As Date End Class
Public Class Customer Private _lastname As String Private _firstname As String End Class Public ``` You will just have to imagine all the properties and constructors that go with that model.
Now I have to make a report that gives me an invoice with a field that joins lastname and firstname of the customer. And for some bizarre reason, customer is not a required field. This means that customer can be nothing.
If customer is nothing and you have
=First(Fields!Customer.Value.LastName) & ” ” & First(Fields!Customer.Value.FirstName)
in your value of the textbox, then it will show you#Error
which is not a desired effect we would like it empty or say “No customer needed”.
You could try this
=iif(First(Fields!Customer.Vaulue is nothing,”no customer needed”,First(Fields!Customer.Value.LastName) & ” ” & First(Fields!Customer.Value.FirstName)
but that will still give you #Error, since in the iif all the members are evaluated. So you have to take more drastic measures.
You will have to make a custom code like this solution shows.
Something like:
vbnet
Public Function ConvertValue(ByVal value As Object) As String
If IsNothing(value) Then
Return Nothing
Else
Return Format(CDec(value),"(###) ###-####")
End If
End Function
Or you could change the domainmodel and add a property Lastnameandfirstname. Anyway, I think the better solution is to do something like this:
```vbnet Public Class ReportInvoice Private _total As String Private _customerNameandfirstname As String Private _invoicedate As String
Public Sub New(ByVal Invoice As Invoice)
_total = Invoice.Total.ToString("0.00 €")
If Invoice.Customer IsNot Nothing Then
_customerNameandfirstname = Invoice.Customer.Lastname & " " & Invoice.Customer.Firstname
Else
_customerNameandfirstname = "customer not known"
End If
_invoicedate = Invoice.InvoiceDate.ToString("dd/MM/yyyy")
End Sub
End Class``` This will make it very easy to design the report since all the fields are there and when you switch reporting engines, making the new reports will be a lot faster since you don’t have to rewrite all the custom code.
Does that make sense?