davin

Just a little thinking and interest!

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

     之前一段时间对存储过程(store proceduce 简称sp)在EF中的使用非常感兴趣,所以看了一些相关的资料,也断断续续的做 了一些练习。最近2个月下班后就不愿意再写代码了,所以也只能在周末睡眠足够之后做些感兴趣的事.关于sp在EF的使用,最基本资料就是msdn了,不过中午睡醒起来看到Ado.team blog上出现了一篇文章关于EF的msdn添加了新 内容,其中有关于如何自定义function,DefineQuery。

     使用EF也有一段时间了,不过对于entity client的了解却知之甚少,因为通过设计EDM,访问ObjectContext,可以说在某种程度上甩掉了那一层层所谓的包装。不过之前学习存储过程sp在EF中的使用时,我发现在某些时候EDM并不能完全解决.如果对于sp在EDM的映射有一些了解的话,可以很清楚的明白,在EDM中映射一个sp返回的类型包括:Entity Type,Scalars Type,None;这三中类型分别对应的sp返回内容对应到数据库,表的层面就是:(Entity)一张表的所有字段或若干字段(必须包括主键);(Scalars)返回一个常量(int, varchar)可以是数据库的一个字段,可以是sum,count,left...等函数操作的结果;(none)自然是什么都不返回.这里自然就有一个严重的问题,对于返回(multiple result sets)多张表的结果集怎么办?似乎entity client能做到,于是我做了一些尝试:

    //execute stored proceduce with entityclient
        public static IList<OrderDetails> entityClientCommand(NorthWind.NorthwindEFEntities context, int OrderID)
        {
            EntityConnection conn 
= context.Connection as
 EntityConnection;
            IList
<OrderDetails> list = new List<OrderDetails>
();
            
//EntityConnection expose a StoreConnection

            DbConnection dbconn = conn.StoreConnection;
            DbCommand dbcmd 
=
 dbconn.CreateCommand();
            dbcmd.CommandText 
= "GetOrderDetails"
;
            dbcmd.CommandType 
=
 CommandType.StoredProcedure;
            dbcmd.Parameters.Add(
new SqlParameter("OrderID"
, OrderID));
            
if ((dbcmd.Connection.State ==
 ConnectionState.Closed))
                dbcmd.Connection.Open();
            
try

            {
                
using (DbDataReader reader = dbcmd.ExecuteReader())
                {
                    
while
 (reader.Read())
                    {
                        
// Gets the column ordinal given the name of the column,

                        int IDOrdinal = reader.GetOrdinal("OrderID");
                        
int UnitPriceOrdinal = reader.GetOrdinal("UnitPrice"
);
                        
int QuantityDOrdinal = reader.GetOrdinal("Quantity"
);
                        OrderDetails od 
= new
 OrderDetails
                        {
                            OrderID 
=
 reader.GetInt32(IDOrdinal),
                            UnitPrice 
= reader.IsDBNull(UnitPriceOrdinal) ? decimal
.Zero : reader.GetDecimal(UnitPriceOrdinal),
                            Quantity 
=
 reader.GetInt16(QuantityDOrdinal)
                        };
                        list.Add(od);
                    }
                }
            }
            
finally

            {
                
if (dbcmd.Connection.State == ConnectionState.Open)
                {
                    dbcmd.Connection.Close();
                }
            }
            
return
 list;
        }

     从上面的这段代码可以看出我们可以使用EntityClient通过EntityConnection.StoreConnection来执行存储过程,因为StoreConnection是一个Dbconnection,所以的操作都和SqlClient很类似。通过DbDataReader将sp执行的结果具体为某一个实体或多个结果(上面的示例是返回一个实体,返回多个实体也肯定可以,不过需要更麻烦一些).尽管上面的做法可以处理返回内容为multiple result sets,但毕竟不能直接返回。不过后来看到了ms发布的EF Extension,在那个扩展包里就添加了对于sp返回multiple result sets的扩展。下面是我是我添加EF Extension之后在EntityClient调用sp的代码:

        //exec stored proceduce with EF Extension
        public static IEnumerable<OrderDetails> ExtensionCommand(NorthwindEFEntities context, int OrderID)
        {
            DbCommand cmd 
= context.CreateStoreCommand("GetOrderDetails", CommandType.StoredProcedure, new SqlParameter("@OrderID"
, OrderID));
            var result 
= cmd.Materialize<OrderDetails>
().Bind(context);
            
return
 result;
        }

  可以看出entityClientCommand与ExtensionCommand在代码量上的差距(entityClientCommand返回的OrderDetails实体的属性不是所有都有值,因为在DbDataReader里面我没有取出所有的column,否则会更多,再看看执行的效果

using (NorthwindEFEntities context = new NorthwindEFEntities())
            {
                IList
<OrderDetails> list = StoredProduceExtension.entityClientCommand(context, 10248
);
                
foreach (var item in
 list)
                {
                    Console.WriteLine(
"entityClientCommand:{0},{1},{2},{3}"
, item.OrderID, item.UnitPrice, item.Quantity, item.EntityState);
                }
                IEnumerable
<OrderDetails> enumerable = StoredProduceExtension.ExtensionCommand(context, 10248
);
                
foreach (var item in
 enumerable)
                {
                    Console.WriteLine(
"ExtensionCommand:{0},{1},{2},{3}"
, item.OrderID, item.UnitPrice, item.Quantity, item.EntityState);

                }
                
//
 DisplayResults<OrderDetails>(enumerable);
               
// IEnumerable<OrderDetails> enumerable1 = StoredProduceExtension.ExtensionCommand1(context, 10248);


            }
      

    输出结果并不是完全一样,OrderDetails实体的内容是一样的,但是EntityState的值不一样,在EF中object services 的实体跟踪服务Tracking Service是一种很重要的行为,entityClientCommand返回的实体OrderDetails状态值是Detached表明实体存在,但是不在当前objectcontext对象的object Services 跟踪之内。Unchanged表明已经被Tracking.具体关于查看EntityState值的说明。

    没想到已经是12.21了, 不过好像我还没有说明EF Extension是怎样处理mulplite result set,就已经很困了。对于EF Extension还有很多值得令人兴奋的地方。最后再介绍2篇学习sp&EF的文章Stored Procedure Mapping,Migrating from LINQ to SQL to the Entity Framework: Stored Procedures for data retrieval

posted on 2008-12-21 00:14  davin  阅读(3127)  评论(2编辑  收藏  举报