在本文中,将探讨如何利用Entity Framework(EF)的元数据来创建动态报告。这种方法的核心思想是,从EF的映射中收集所需表格和列的信息,然后构建一个SQL查询,以返回客户所需的信息。这种方法的主要优势在于:
创建了一个小型库,使用描述的方法来简化动态报告的工作。所有源代码都可以在GitHub上找到:
以下是使用这个小型库在项目中快速设置动态报告的步骤:
本文不涵盖使用Entity Framework的所有细节,但可以在这里找到许多有用的文章。在演示项目中,将使用一个简单的数据库模式,其中包含学校学生的信息。
public class Student {
[Key]
public int StudentId { get; set; }
public string FirstName { get; set; }
// 省略了一些代码...
}
public class SchoolDbContext : DbContext {
public DbSet Students { get; set; }
// 省略了一些代码...
}
对于每个报告,应该声明报告中将包含哪些列。在案例中,使用报告模板类StudentsReport,它包含报告中所有可用列的信息。
public class StudentsReportTemplate : ReportTemplate {
// 省略了一些代码...
public override IEnumerable<IReportColumn> ReportColumns {
get {
return new List<IReportColumn> {
StudentTable.Column("First Name", x => x.FirstName),
StudentTable.Column("Last Name", x => x.LastName),
StudentTable.Column("Phone", x => x.Phone),
StudentTable.Column("Home Address", x => x.HomeAdress),
new AverageScore(queryExtractor, StudentTable).Column("Average Score"),
new MinimumScore(queryExtractor, StudentTable).Column("Minimum Score"),
new MaximumScore(queryExtractor, StudentTable).Column("Maximum Score"),
new Age(StudentTable).Column("Age"),
new Subjects(queryExtractor, StudentTable).Column("Subjects")
};
}
}
public override IReportDataSource ReportDataSource {
get {
return StudentTable.GetReportDataSource();
}
}
}
每个声明都声明了报告可能包含的一个列。例如:StudentTable.Column("First Name", x => x.FirstName)声明报告可以包含学生的名字。
在配置了报告模板之后,可以从中创建报告模型。
StudentsReportTemplate template = new StudentsReportTemplate(...);
// 报告模板创建IReportModel对象,它不依赖于具体的报告模板。
IReportModel reportModel = template.CreateReport();
// 为了获取报告数据,指定想在报告中看到哪些列和过滤器(所有列都应该存在于报告中,详见步骤 #2)
var filters = new IReportFilter[0];
var columns = new IReportColumn[] {
new ReportColumn { Title = "First Name" }
};
var data = reportModel.Get(columns, filters);
例如,关于学生平均分数的报告将如下所示:
SELECT
(SELECT AVG(e.Score) FROM ExamenResults as e WHERE e.StudentId = s.StudentId) AS AverageScore,
s.FirstName AS FirstName,
s.LastName AS LastName
FROM [dbo].[Students] AS s