C# 自定义即席报告体系结构

C# 自定义即席报告体系结构,c#,nhibernate,architecture,reporting,metamodel,C#,Nhibernate,Architecture,Reporting,Metamodel,我将描述我试图实现的目标,并感谢对如何设计解决方案的架构和技术建议 我正在开发一个应用程序,它需要允许最终用户从有限的数据集创建临时报告。以下是我正在努力克服的全球障碍: 报表设计与元模型 最终用户应能够完成报告向导,该向导包括以下步骤: 选择报表根实体,它是所有关系的根 在根实体的属性上创建筛选器 在与根实体(例如客户、用户)相关的其他实体的属性上创建筛选器 从选定关系中所有列的并集中选择报表表的列 选择排序表达式 选择分组表达式 保存报告 这在商业应用程序中很常见,SugarCRM就是一个很

我将描述我试图实现的目标,并感谢对如何设计解决方案的架构和技术建议

我正在开发一个应用程序,它需要允许最终用户从有限的数据集创建临时报告。以下是我正在努力克服的全球障碍:

报表设计与元模型

最终用户应能够完成报告向导,该向导包括以下步骤:

选择报表根实体,它是所有关系的根 在根实体的属性上创建筛选器 在与根实体(例如客户、用户)相关的其他实体的属性上创建筛选器 从选定关系中所有列的并集中选择报表表的列 选择排序表达式 选择分组表达式 保存报告 这在商业应用程序中很常见,SugarCRM就是一个很好的例子

我打算定义一个自定义的元模型来描述报告。 应用程序使用NHibernate作为ORM,其思想是使用CriteriaAPI来构造报表查询,所以元模型应该包含查询投影、连接、过滤器、排序和分组表达式所需的所有数据。是否有一个元模型的例子,我可以适应这个解决方案

在技术方面,存在以下问题:

浏览现有数据模型

如何从数据模型中提取字段和关系?首先想到的是使用反射,但由于用户可以向实体添加自定义字段,而不会更改实体类,因此这不是解决方案。剩下的是数据库本身或NHibernate映射文件。Nhibernate是否为此公开API,或者手动XML查询是唯一的选择

报表呈现

同时,在上呈现报告也是一个问题。报告必须在运行时设计,但据我所知,这是不可能与rdlc。这种方法的替代方案是什么? 避免使用rdlc并以普通HTML呈现?还有其他框架吗


对于实现这些特性并可作为灵感的开源c、java项目的建议也很受欢迎。

可以使用创建临时报告。PdfReport是一个代码优先的报告引擎,它构建在iTextSharp和EPPlus库之上。
它与.NET 3.5+Web和Windows应用程序都兼容。PdfReport支持范围广泛的数据源,从数据表到内存中的强类型列表,而无需数据库:

可以使用创建临时报告。PdfReport是一个代码优先的报告引擎,它构建在iTextSharp和EPPlus库之上。 它与.NET 3.5+Web和Windows应用程序都兼容。PdfReport支持范围广泛的数据源,从数据表到内存中的强类型列表,无需数据库:

报表设计和元模型 数据模型需要关联路径、列名和列索引

e、 g

浏览现有数据模型 NHibernate通过Configuration.ClassMappings和Configuration.GetClassMappingType或usefull reflection Optimized access公开详细的元数据,并通过ISessionFactory.GetClassMetadataType公开一些元数据最重要的是PropertyNames、GetPropertyValueobj、name、mode.Poco

报表呈现 我在这里无能为力

报告设计和元模型 数据模型需要关联路径、列名和列索引

e、 g

浏览现有数据模型 NHibernate通过Configuration.ClassMappings和Configuration.GetClassMappingType或usefull reflection Optimized access公开详细的元数据,并通过ISessionFactory.GetClassMetadataType公开一些元数据最重要的是PropertyNames、GetPropertyValueobj、name、mode.Poco

报表呈现
这里我无能为力

谢谢你的回答,我希望NHibernate有这样的api。这应该足以涵盖浏览数据模型的问题。谢谢你的回答,我希望NHibernate有这样的api。这应该足以解决浏览数据模型的问题。Tnx,这看起来是动态即席报告的一个很好的解决方案Tnx,这看起来是动态即席报告的一个很好的解决方案
class Report
{
    public Layout Layout { get; set; }
    public string EntityTypeFullName { get; set; }
    /// each Filter is a compare on one Property
    public ICollection<Filter> Filters { get; }
    public IList<Column> Columns { get; }
}

class Column
{
    public string HeaderText { get; set; }

    /// e.g. Contract.User.Name
    public string AssociationPath { get; set; }
}

// in code
var query = session.CreateCriteria(EntityTypeFullName);
// recursive method which adds simple properties as Restrictions and calls itself
// with query.CreateCriteria(referencePropertyName, Filters.Select(CropAssociationPath));
AddFilter(query, report.Filters)