创建可重复使用的 Linq To SQL 存储过程

17

我正在开发一个需要使用 Linq To SQL 的新项目。我被要求创建一个通用或可重复使用的 Linq to SQL 类,以便执行存储过程。

ADO.Net 中,我知道可以通过传递要执行的字符串来实现此操作,我可以为每个需要运行的查询传递不同的参数字符串:

SqlCommand cmd = new SqlCommand("myStoredProc", conn); // etc, etc

我正在努力学习如何在 Linq To SQL 中创建类似的东西,如果可能的话。我已经创建了一个 .dbml 文件并将我的存储过程添加到其中。因此,我可以使用下面的代码返回结果:

public List<myResultsStoreProc> GetData(string connectName)
{
   MyDataContext db = new MyDataContext (GetConnectionString(connectName));
   var query = db.myResultsStoreProc();

   return query.ToList();
}

代码有效,但他们希望我创建一个方法,可以返回我告诉它要运行的任何存储过程。我已经在网上搜索并与同事讨论了这个问题,但没有找到创建可重用存储过程类的方法。

那么,有没有一种方法可以创建一个可重用的 Linq to SQL 类来执行存储过程?

编辑:

我想知道是否有一种方法可以做到像下面这样的操作?

public List<string> GetData(string connectName, string procedureName)
{
   MyDataContext db = new MyDataContext (GetConnectionString(connectName));
   var query = db.procedureName();

   return query.ToList();
}

我已经查阅了关于Linq To SqlMSDN文档,其中显示了IEnumerable中的表格:

IEnumerable<Customer> results = db.ExecuteQuery<Customer>(
   @"select c1.custid as CustomerID, c2.custName as ContactName
      from customer1 as c1, customer2 as c2
      where c1.custid = c2.custid"
);

我正在寻找一种非常通用的方法,可以发送一个字符串值来执行所需的存储过程。如果这不可能,是否有任何关于为什么不能以这种方式进行的文档?我需要证明为什么我们无法在 Linq To Sql 中传递要执行的过程名称的字符串值。


您是否需要执行未在.dbml文件中建模的存储过程?并且您是否希望返回在.dbml中映射的实体? - CodingGorilla
它们很可能会被映射在.dbml中,但我猜可能存在一种情况,即它没有被映射。 - Taryn
@usr 我认为它不应该这样使用。但是项目负责人想知道是否可能。所有代码都应尽可能可重用。 - Taryn
你已经拥有了一种可重复使用的调用任何存储过程的方法:将其导入到dbml中,并在数据上下文中调用它。不管怎样,这是你的决定。 - usr
1
为 DapperDotNet 欢呼三声!http://code.google.com/p/dapper-dot-net/ - Chris Pfohl
显示剩余3条评论
3个回答

18

DataContext.ExecuteCommand并不是你所需要的,因为它只返回一个int值。相反,你需要的是DataContext.ExecuteQuery,它能够执行存储过程并返回数据集。

我会创建一个DBML的部分类来存储这个函数。

public List<T> GetDataNoParams(string procname)
{
   var query = this.ExecuteQuery<T>("Exec " + procname);

   return query.ToList();
}

public List<T> GetDataParams(string procname, Object[] parameters)
{
   var query = this.ExecuteQuery<T>("Exec " + procname, parameters);

   return query.ToList();
}

要调用存储过程,您需要执行以下操作:
GetDataNoParams("myprocedurename");

GetDataParams("myotherprocedure {0}, {1}, {2}", DateTime.Now, "sometextValue", 12345);

或者

GetDataParams("myotherprocedure var1={0}, var2={1}, var3={2}", DateTime.Now, "sometextValue", 12345);

如果你想调用没有返回值的过程,那也很容易,只需创建一个不存储/返回任何内容的新方法即可。这个灵感来自于http://msdn.microsoft.com/en-us/library/bb361109(v=vs.90).aspx

DBML文件会告诉ExecuteQuery<T>方法T的类型,以便数据可以被映射到对象实例中吗? - bluevector
不,你在调用它时告诉它是什么。我的示例假设您已经将对象映射到每个存储过程的返回类型。因此,如果您有一个返回客户的存储过程,并且有一个客户对象类型,则将Customer传递给T。 - Peter
明白了,我们不需要将存储过程转换为IQueryable,也不需要什么全知全能的东西。 - bluevector
没错,这更像是标准的DataAdapter.Fill命令,它只返回您想要的数据枚举。如果您想重新连接该数据以执行IQueryable操作,则需要更多的工作,例如您可能需要使用ID再次从数据库获取对象。但是,如果您只需要进行过滤/排序等操作,您始终可以使用Linq to objects。 - Peter
@Peter 感谢你提供的指引,它让我朝着正确的方向前进。不过还在处理一些问题。 - Taryn

2
您的问题最简单的答案是,您可以获取MyDataContextConnection属性,并创建和执行您自己的SqlCommand,就像在纯粹的ADO.Net中一样。但我不确定这样是否适合您的目的,特别是如果您想从LINQ到SQL模型中检索实体。
如果您想返回模型中的实体,则可以查看DataContext.ExecuteCommand方法。

谢谢您提供的指导,但您能否提供更多关于如何传递我想要执行的过程名称字符串的信息。 - Taryn
@bluefeet,请看Peter的回答,他提供了几个不错的例子。 - CodingGorilla

0
当我们在.dbml文件中删除一个表或存储过程时,它会创建与数据层和业务逻辑通信的类。
在Linq to SQL中,我们必须在.dbml文件中存在存储过程或表,否则就没有办法调用Linq to SQL中的通用方法来通过将其名称传递给方法来调用存储过程。
但是在ADO.Net中,我们可以这样做(就像你知道的那样)。
SqlCommand cmd = new SqlCommand("myStoredProc", conn);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接