【问题标题】:How to create a complex type from a stored procedure that uses exec()?如何从使用 exec() 的存储过程创建复杂类型?
【发布时间】:2011-04-13 06:59:23
【问题描述】:

我想通过动态构造并使用exec() 执行的查询创建一个复杂类型以在实体管理器中使用。可能吗?;由于我正在编写过滤器,如果不可能,您会怎么做?

另外,我正在使用 linq 进行评估,但过滤器需要许多表及其寄存器,因此效率是一个问题。

谢谢...

【问题讨论】:

  • 我很好奇这个 exec() 是返回多个记录集还是一个?
  • 它在一个 tsql 过程上执行一个 sql 命令
  • 这种查询正是 LINQ2EF 的用途。当您在服务器上exec 时,您不仅失去了预编译的好处,还失去了参数化查询所获得的缓存执行计划的好处。

标签: c# sql-server linq tsql stored-procedures


【解决方案1】:

是的,您可以在上面使用 Entity Framework 4 和 LINQ,它会生成参数化查询并执行它,这就是选项。

另一种选择是(我做过几次)创建一个基类/接口,比方说:

public interface IExecutable
{
    void Execute(IConnection connection);
}
public interface IExecutable<TResult> : IExecutable
{
    TResult Result { get; }
}

public abstract ActionBase<TResult> : IExecutable<TResult>
{
    protected void AddParameter(....);

    protected IDataReader ExecuteAsReader(string query) {
        //create a DB Command, open transaction if needed, execute query, return a reader.
    }

    protected object ExecuteAsScalar(string query) {
        //....
    }

    //the concrete implementation
    protected abstract TResult ExecuteInternal();

    IExecutable.Execute(IConnection connection) {
        //keep the connection
        this.Result = ExecuteInternal();
    }

    //another common logic: 

}

然后你可以创建你的具体行动:

public sealed class GetUsersAction : ActionBase<<IList<User>>
{
    //just a constructor, you provide it with all the information it neads
    //to be able to generate a correct SQL for this specific situation
    public GetUsersAction(int departmentId) {
        AddParameter("@depId", departmentId);
    }

    protected override IList<User> ExecuteInternal() {
        var command = GenerateYourSqlCommand();

        using(var reader = ExecuteAsReader(command)) {
            while(reader.Read) {
                //create your users from reader
            }
        }
        //return users you have created
    }
}

很容易创建具体的动作!

然后,为了更简单,创建一个 ExecutionManager,其关注点是如何获取连接并执行操作:

public sealed ExecutionManager() {

    TResult Execute<TResult>(IExecutable<TResult> action) {
        var connection = OhOnlyIKnowHowTOGetTheConnectionAnfHereItIs();
        action.Execute(connection);
        return action.Result;
    }
}

现在就用它吧:

var getUsersAction = new GetUsersAction(salesDepartmentId);

//it is not necessary to be a singletone, up to you
var users = ExecutionManager.Instance.Execute(getUsersAction);

//OR, if you think it is not up to ExecutionManager to know about the results:
ExecutionManager.Instance.Execute(getUsersAction);
var users = getUsersAction.Result

使用这种简单的技术,很容易将所有连接/命令/执行逻辑从具体操作转移到基类中,具体操作的关注点只是生成 SQL 并将数据库输出转换为一些有意义的结果。

祝你好运:)

【讨论】:

  • 嗯...是的...但是直接在数据库上...我问这个是因为我们希望存储过程完全包含在数据库中。
【解决方案2】:

如果您决定采用 Linq 路线并正在寻找一种进行过滤的好方法。 LinqKit 是一个很棒的库,用于构建临时谓词。内置 linq 库的问题在于您只能临时组合 AND 语句,而不能临时组合 OR 语句。 Linqkit 让这一切变得轻而易举。

【讨论】:

    猜你喜欢
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    相关资源
    最近更新 更多