0

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

例子:

架构

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(不是核心)。

4

2 回答 2

0

我用一种解决方法临时解决了这个问题。

我不会接受我的回答,因为我认为这不是最佳做法,也许其他人会提出更好的解决方案。这个解决方法对我有用,因为我只想阅读权限。如果您选择实施此解决方案,请小心并检查它生成的 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());
于 2018-02-15T09:43:02.313 回答
0

根据您的复杂表结构,这可能有效或无效。您基本上可以从 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 });

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

于 2018-02-14T07:21:48.023 回答