【问题标题】:Configure Entity Framework to call a SQL Server table function instead of a table on a specific entity将实体框架配置为调用 SQL Server 表函数而不是特定实体上的表
【发布时间】:2018-02-14 07:01:20
【问题描述】:

我有一个实体表(比方说文档),其中每个文档可能有不同的实体连接到它(比方说权限)。权限具有文档表的外键。

例子:

架构

Document -> Id | Data
Permission -> Id | EntityId | PermissionData

内容

Document -> 1 | "This is my first doc"
Permission -> 12 | 1 | "This is doc 1's permission set"

如果Permission 是一个表,我不会有任何问题 - 我只需在查询中使用Include 方法并获得连接权限:

ctx.Include(d => d.Permission)...

但是,Permission 实际上是一个复杂的方案,它包含多个表,并且使用 SQL Server 表值函数进行计算。

我正在尝试创建一个Permission 实体,就像每个常规表实体一样,并且只需将实体框架配置为执行数据库函数调用而不是表连接。

如果权限是一个表并且我会将它包含在我的查询中,我希望 SQL 执行看起来像这样:

select * 
from document d 
join permission p on d.Id = p.EntityId

我想实现这样的目标:

select * 
from document d 
join fn_getPermissions(p1,p2,p3...) p on d.Id = p.EntityId

假设参数 p1...pn 是硬编码的,但我需要在 C# 端而不是在 SQL Server 中默认它们。

我看到了一个使用 Entity Framework 配置实体以使用存储过程的选项,但我没有看到任何地方可以使用存储过程进行查询,而不是插入、删除等。

我知道如何调用DBFunctions(使用Conventions)——我不是在寻找显式的函数调用。我想将 Permission 实体视为表实体,主要是因为我在实体框架上使用 OData,并且我不想仅为这种情况创建特定方法。

有没有办法完成这种行为?我使用的是 EF 6.x(不是核心)。

【问题讨论】:

  • 您可以创建一个视图,将权限拆分为行,然后您可以随意查询它
  • @Monah - 我想过这样做,但我有多个实体,如文档,我更喜欢以某种方式配置实体框架。
  • 您能否提供有关权限数据以及这些实体有何不同的更多详细信息? IMO,这里的视图方法最适合您的情况
  • @Monah - 有多个表定义了权限方案。有多个实体(如文档)在逻辑上共享该权限方案。有一个函数可以进行大量计算并根据输入参数返回答案,我可以在 C# 代码中根据请求全局访问这些参数,因此,我说我现在可以使用硬编码参数。
  • 我怀疑这很容易实现 - 实体框架并不以其出色的可扩展性而闻名。

标签: c# sql-server entity-framework table-functions


【解决方案1】:

根据您的复杂表结构,这可能有效,也可能无效。您基本上可以从 Sql 构造一个实体,但为此您应该在 DB 中有一个实际权限所在的表,即一个包含您想要的所有数据的表(您可以使用其他表来解释它,但您想要的数据是假设仅在权限表中)。比你可以这样使用:

   this.Context.Permissions
.FromSql(@"select permName, permDesc from document d join fn_getPermissions(@p1,@p2,@p3...) p on d.Id = @entityId"
, new SqlParameter("p1", val)
, new SqlParameter("p2", val)
, new SqlParameter("p3", val)
, new SqlParameter("entityId", val))
.Select(c => new { c.permName, c.permDesc });

如您所见,您可以选择一个动态对象,或者如果您想将其转换为一个类型,但您应该浏览一个上下文表,在本例中为“权限”。

【讨论】:

  • 感谢您的回答。这不是我要找的。我知道如何调用 db 函数并明确地做事。由于我在 EF 上使用 OData,因此我正在寻找一个更简洁的通用解决方案。我正在寻找的只是以某种方式告诉实体框架在将表达式转换为 sql 时调用 db 函数而不是表。
【解决方案2】:

我通过解决方法临时解决了这个问题。

我不会接受我的回答,因为我认为这不是最佳做法,也许其他人会提出更好的解决方案。此解决方法对我有用,因为我只想阅读权限。 如果您选择实施此解决方案,请小心并检查它生成的 sql 查询以确保它适合您。

所以,为了实现我所需要的,我将实体映射到一个虚拟表。

modelBuilder.Entity<Permission>().ToTable("Dummy_Permission_Table");

然后,我创建了一个自定义 IDbCommandInterceptor 并覆盖了 ReaderExecuting 方法,因为它是唯一与我的案例相关的方法。

public class PermissionDbCommandInterceptor : IDbCommandInterceptor
{
    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }

    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }

    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
       // get the params and create the function call
       command.CommandText = command.CommandText.Replace("[Dummy_Permission_Table]","fn_getPermissions(p1,p2,p3..)");
    }

    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }

    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }
}

最后,我注册了拦截器:

DbInterception.Add(new PermissionDbCommandInterceptor());

【讨论】:

    猜你喜欢
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    • 2019-01-31
    • 2013-07-13
    相关资源
    最近更新 更多