【问题标题】:Creating a set from Table Valued Function in Entity Framework从实体框架中的表值函数创建一个集合
【发布时间】:2013-08-12 20:00:44
【问题描述】:

我有一个包含非常大表的数据库(其中一些可能有超过 1,000,000 条记录),并且该数据库的每个用户都应该看到其中的一些数据,因此我们有多个 TVF(表值函数)来获取用户 ID并选择该用户可见的表记录(此操作需要多个SELECT 语句,我认为调用 TVF 比在代码中实现它要好得多)。 在向我的客户发布该程序的第一个版本中,我有一个具有多个 IQueryable 类型属性的类,它使用 LinqToSql 实现并且效果很好。 现在我有一个客户想要使用我的程序集来编写 WCF 数据服务,所以我必须编写一个派生自 DbContext(使用 EF) 的类,该类可以在指定的服务中使用。 我的问题是:

  • DbContext 自动暴露其中定义的所有DbSet 属性,因此每个具有最低访问级别的用户都可以看到表的整个数据(当然客户端应用程序会限制数据,但客户端可以访问数据直接,甚至使用 OData 将这些数据导入 Excel 或 Access)

  • 我有多个 IQueryable 类型的公共属性,但它们不会出现在 WCF 数据服务公开的数据列表中。

为了解决这个问题,我认为最完整的解决方案是能够将 TVF 作为一个表来调用,并从中创建一个集合。但我不知道该怎么做?!

注意 对数据库的任何更改都需要一些日志记录,因此我有存储过程来执行这些更改,因此我只需要对我的 WCF 数据服务的只读访问权限,并且我不希望包含在服务中发布的表的所有记录的默认集

【问题讨论】:

  • 我不确定,但我认为您可以使用 Select 语句,就像您要从表中选择来填充数据集一样。
  • @Malachi 感谢您的回答,但我可以(实际上我已经这样做)从我的 TVF 获取 IQueryable,但问题是 WCF 数据服务仅显示我的 DbContext 的所有 DbSet 属性,我想要隐藏所有这些属性并显示我的 IQueryable 属性,但我不知道如何!
  • 你不能创建一个服务类来限制对你的 TVF 的访问吗?

标签: c# entity-framework entity-framework-5 wcf-data-services


【解决方案1】:

我认为你可以通过使用customized data service provider 来定义你的WCF 服务的形状来获得你想要的功能。这可能会变得相当复杂,但由于您已经拥有一堆 IQueryables,您可能可以使用Reflection Provider,文档说:

反射提供程序在返回实现 IQueryable 接口的类型的类中公开数据。 WCF 数据服务使用反射来推断这些类的数据模型,并且可以将针对资源的基于地址的查询转换为针对公开的 IQueryable 类型的基于语言集成查询 (LINQ) 的查询。

该文档链接到“如何”使用反射提供程序。基本上,您只需创建一个具有 IQueryable 属性的伪上下文类,向您的数据对象添加一些属性,并将您的 DataService 指向您的伪上下文类型。 (如果您使用的是数据库/模型优先 EF,您可能需要创建实体的部分以添加属性或更新 T4 模板。)

【讨论】:

  • 非常感谢您的回答,我之前尝试使用 ReflectionProvider 并遇到了一些困难,但我会尝试更改 T4 模板。但是你知道这个技术是否支持 MetadataTypeAttribute 吗?
  • @BigBoss,我很确定它没有;我只是在 System.Data.Services 中的 ReflectionServiceProvider 中进行 dotPeek 操作,它没有使用任何 System.ComponentModel 内容,它只是在数据对象类型上寻找 DataServiceKeyAttribute
【解决方案2】:

为什么不使用 UserID 作为参数创建一个返回记录集的参数化存储过程 (SP)?实体框架可以使用它。

您可以在 SP 中调用您的 TVF,或者只是音译 SP 中的 TVF 内容。

如果您需要添加/删除/更新功能,如果您的查询不可更新,您可能还需要这些功能的 SP。

【讨论】:

  • 第一件事是SQL中的函数不能改变数据库,但SP可以!其次是我不能从 SP 查询数据并期望优化器为我优化它(用 SP 替换 TABLE 是不可能的)但我可以用 TVF 做到这一点,这就是 TVF 存在的原因(我猜)
【解决方案3】:

DbContext 自动公开其中定义的所有 DbSet 属性

我建议,你在数据库中做视图或者使用Linq2Sql模板。

  1. 如果您制作视图,模型设计者会制作适当的数据表。
  2. 如果你使用 linq2sql 模板,
    你可以制作只有 您想向其他人展示的属性。
    (在 linq2sql 上擦除 connectioninfomation 并使用 connctionString 分配后,它只是 如何使用。)

我有多个 IQueryable 类型的公共属性,但它们不会出现在 WCF 数据服务公开的数据列表中。

制作模型并使用 linq 和方法 ExcuteJsonAll。
如果有人收到 JSON 文件,就会有人提供它。

如何将模型制作成存储过程。

  1. 在数据库中选择 SP。

  2. 从数据库更新您的模型

    这里,你带来了 SP。

  3. 在 edmx 或模型视图中,您使用 SP 制作函数。

  4. 在创建函数的过程中,可以让sp的DataSet相关返回值。

【讨论】:

  • 感谢您的帮助,但由于我有很多用户(用户可以创建新用户),因此 VIEW 无法正常工作,因此我无法为每个用户创建新视图,如果我应该如何将它们与 EF 一起使用??
  • 也许,问题是返回 IQueryable。模型的属性对用户开放。您应该进行选择程序。并且...从 select sp 中,您制作模型。
  • 只是返回 IQueryable,不解决问题,我已经能够从 TVF 返回一个 IQueryable,这从 SP 中具有更好的性能。但问题是所有集合都将通过数据服务发布,用户可以下载它们,而且 IQueryable 类型的属性也不会由 DataService 发布,因此用户无法使用 OData 的普通工具下载它们,只能访问该数据以编程方式。所以我们发布了无效数据并隐藏了正确的数据!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-30
  • 2013-08-29
  • 2013-01-30
  • 1970-01-01
  • 2013-07-11
相关资源
最近更新 更多