存储过程(sp)在EDM中的使用,相比于sp在EDM中的functionImport,似乎我更关心sp在EDMX文件中的表现.
当我将存储过程sp GetOrder添加到EDM并完成FunctionImport之后,我就可以打开EDMX文件,查看关于GetOrder在ssdl(),csdl,c-s mapping中的实现:
sdl: <Function Name="GetOrder" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<Parameter Name="OrderID" Type="int" Mode="In" />
</Function>
关于function中的参数:对于IsComposable,BuiltIn这2个参数非常重要,用于指定返回结果将由存储过程的查询来返回,不需要生成其它的sql(针对linq,及时不需要被解释),因为均设为false,其它的没什么好说的。
csdl: <FunctionImport Name="GetOrders" EntitySet="Orders" ReturnType="Collection(NorthwindEFModel.Orders)">
<Parameter Name="OrderID" Mode="In" Type="Int32" />
</FunctionImport>
ReturnType是一个Collection,我曾尝试将其修改为单一实体(让其返回一个非集合类型),不过在EF v1中并不支持.
如果sp在edmx文件中就仅仅如此,那真的没什么可写了.不过并不仅仅如此,因为除了Return Type之外还有CommandText,out put 参数.
.CommandText
在Function的xml节点下面有CommandText这个标签,CommandText可以让我们在ssdl层的function中自定义sql,而非仅仅局限于sp,在某些特定的场景中将sql嵌入ssdl层中要好过sp,毕竟sp是存在数据库上,这使得不仅要管理应用程序还需要管理数据,function中的CommandText属性可以2者达到某种平衡.下面是使用CommandText的例子
ssdl:<Function Name="CustomerWithHighestSales" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<!-- cannot use command text with functions. allows to execute multiple statement.-->
<CommandText>
select *
from Customers
where CustomerID = (
select top 1 o.CustomerID
from Orders o
join OrderDetails od
on o.OrderID = od.OrderID
group by o.CustomerID
order by SUM(od.UnitPrice * od.Quantity) desc )
</CommandText>
</Function> ssdl中的CommandText内容是找出HighestSales的Customer
Csdl: <FunctionImport Name="CustomerWithHighestSales" EntitySet="Customers" ReturnType="Collection(NorthwindEFModel.Customers)">
</FunctionImport>
msdl: <FunctionImportMapping FunctionImportName="CustomerWithHighestSales" FunctionName="NorthwindEFModel.Store.CustomerWithHighestSales" />
而使用CustomerWithHighestSales这个方法,和之前的并没有任何不同.
using (NorthwindEFEntities context = new NorthwindEFEntities())
{
var customer = context.CustomerWithHighestSales().First();
Console.WriteLine("{0}", customer.CustomerID);
}
.out put 参数,当我一直在调用sp相应的方法是,总是传入参数,所以我很想尝试对于带有out put参数的sp的处理,不过很遗憾的是在EF v1中不直接支持带有out put参数的sp.当我在数据库创建一个带参数的sp getTotolOrdersForCust,在模型浏览器进行FunctionImport后,我查看edmx文件没有看到1任何相关getTotolOrdersForCust的内容,后来在EF社区得到了EF v1不支持带out put参数的sp.当然只是说不直接支持,但 可以通过自定义来解决
Ssdl: <Function Name="getTotolOrdersForCust" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
<Parameter Name="CustomerID" Type="nchar" Mode="In" />
<Parameter Name="Count" Type="int" Mode="Inout" />
</Function>
Csdl: <FunctionImport Name=" getTotolOrdersForCust ">
<Parameter Name="CustomerID" Type="nchar" Mode="In" />
<Parameter Name="Count" Type="int" Mode=="InOut" /></FunctionImport>
Msdl: <FunctionImportMapping FunctionImportName="getTotolOrdersForCust" FunctionName=" NorthwindEFModel.Store.getTotolOrdersForCust" />
而剩下的代码则可以写成这样:
public void CustomerWithHighestSales(string customerID, ref int totalOrders)
{
var dbparams = new DbParameter[] {
new EntityParameter { ParameterName = "CustomerID", DbType = DbType.String, Value = customerID },
new EntityParameter { ParameterName = "Count", DbType = System.Data.DbType.Int32, Direction = ParameterDirection.Output }
};
DbCommand cmd = this.Connection.CreateCommand();
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddRange(dbparams);
cmd.CommandText = this.DefaultContainerName + "." + "getTotolOrdersForCust";
if (cmd.Connection.State == System.Data.ConnectionState.Closed)
{ cmd.Connection.Open(); }
cmd.ExecuteNonQuery();
totalOrders = Convert.ToInt32(dbparams[1].Value);
}