MVC3+EF4.1学习系列(十一)----EF4.1常见的问题解决

博客写了10篇了~有很多朋友私信问了一些问题,而且很多问题 大家问的都一样 这里说说这些常见问题的解决办法.如果大家有更好的解决办法~也希望分享出来

问题大概为这几个

一.ef4.1 codeFirst 修改表结构 增加字段等 EF code first需要重新生成库导致数据丢失的问题.

二.ef4.1 没有了edmx等复杂的东西 变得简单 干净  但如何使用存储过程,存储过程可以返回表 可以返回数值 也有可能是执行修改 删除 增加等  该怎么做?

三.ef4.1 如何使用数据库视图?每个视图都要去建立对应的实体类么?有简单的方法么?

四.ef4.1 如何执行SQL函数等操作?

五.ef4.1 如何跨数据库访问?

六.ef4.1执行连接查询?什么时候执行左连接? 什么时候执行内连接? ef 根据什么去判断?

七.新手使用ef4.1 常见的一些报错信息

八.ef4.1返回datatable 方便做报表等一些复杂操作

其实这些问题是比较简单的~ 所以此文送给刚用ef4.1的新手~

下面开始一一解决这些问题

一.ef4.1 codeFirst 修改表结构 增加字段等 EF code first需要重新生成库导致数据丢失的问题

说这个问题前 首先先说下 我使用ef4.1 codefirst的目的. 是因为可以有更纯净的POCO 不再有EDMX这些东西  而不是真正的用 code first 先有代码 再生成数据库.所以 我虽然使用

的是codefirst 但是本质依然是数据库优先.

所以这个被问的很多的问题 解决办法其实是非常简单的.只要你的数据库已经存在了 那么即使你用code first ef 也不会给你去生成数据库的. 这个时候 你增加表字段 甚至增加表 只要把

实体类也相应的修改 则数据库里的数据 是不会被清空的.

说下我的开发步骤  先设计数据库 并建立数据库=>通过EF工具生成映射和实体类=>开发代码     当遇到修改时=>  先修改数据库如添加字段或表等=>再修改实体类=>继续开发

这样就不会有重新生成数据的烦恼了 而且项目里也不会出现edmx~

还有 使用EF4.3 的数据迁移功能 也可以完美解决~

二.ef4.1 没有了edmx等复杂的东西 变得简单 干净  但如何使用存储过程,存储过程可以返回表 可以返回数值 也有可能是执行修改 删除 增加等  该怎么做?

说这个问题前 依然先说下我的观点.个人认为 既然使用orm框架  就应该把业务逻辑等 都放到业务逻辑层 而不应该再使用存储过程。我更偏重重业务逻辑层 轻存储过程这样的开发~

再ef4.0里 添加存储过程 比较容易 有edmx 调一调 存储过程就添加上了 但是在ef4.1里 只有干净的poco 不再有edmx了 改怎么办呢?尤其是存储过程可以是查表 查值 或者执行修改删除.

一个一个来解决

1.执行返回表类型的存储过程

先上存储过程 随手写的一个最简单的

Create PROCEDURE [dbo].[ProSelectStu]    @StudentID intASBEGIN

Select Student.* from Enrollment,Student where Enrollment.StudentID=Student.StudentIDand [email protected]

END

GO

执行存储过程的方法 是用直接执行sql的方式 我在我的文章第九篇 有过详细的介绍~大家可以先去看下

执行表的存储过程 其实是非常强大的 延迟加载 等都有体现 博客园的陆老师已经写了 写的非常清楚了~我这里就不再写了 大家可以去他那看下 提供个连接~

EF使用存储过程查询表的

2.执行返回值的存储过程

先上存储过程

CREATE PROCEDURE [dbo].[ProSelectCount]    @StuId intASBEGIN    select COUNT(*) from Enrollment where [email protected]END

一个简单的查询数量

这里用sqlQuery 执行访问 数据库 因为需要提供返回类型 而我们返回的是int 所以先得到int的类型

3.执行增删改

CREATE PROCEDURE [dbo].[ProDel]    @stuId int,    @courseId intASBEGIN

DELETE FROM [WLFSchool].[dbo].[Enrollment]     where [email protected] and [email protected]

END

这个用的是操作数据库 返回受影响行数

三.ef4.1 如何使用数据库视图?每个视图都要去建立对应的实体类么?有简单的方法么?

先说下最传统的方法 只需把视图 当成表 建立对应的实体类  然后加到dbcontext 里即可。没什么难度。

再说一个问题 使用linq 有个非常美妙的功能 投影映射 和C#3.0的 匿名函数 让我们很多情况 不需要视图的

                                  from c in classes                                  from s in students                                  where c.ClassID == s.ClassID                                  order by c.CreateTime                                  select new                                  {                                      Name = s.Name,                                      Age = s.Age,                                      ClassName = c.ClassName                                                                  };

再通过  var result 接受上面的值  这样我们就不用去数据库建视图 不用再建实体类 是不是很省事呢?

如果公司强大的DBA 已经给我们建好了很多视图 是不是就要一个个去写实体类呢?如果你使用的是C#4.0 那么可以用动态的 来解决这个问题~

像下面这样使用 是不是很爽

这个不仅可以查询视图 普通的表 只要是SQL语句 都可以自动生成动态类 让你用~

下面是扩展方法  和 使用Emit 来动态构建 感谢ASP.NET 韋 给的帮助~~

SqlQueryForDynamic的扩展方法

四.ef4.1 如何执行SQL函数等操作?

添加引用  System.Data.Objects.SqlClient.SqlFunctions 主要是这个命名空间

使用方法~上一个工作中的例子~

var query = from s in student.T_StudentInfo                        where SqlFunctions.DateDiff("day", s.CreateTime, "2011/11/4") == 0                        select s.StudentName;

使用SQL 的datadiff 函数~~

五.ef4.1 如何跨数据库访问?

每次别人问我这个问题 毫不犹豫的把站长dudu的文章发过去~ 他已经很好的解决了~

http://www.cnblogs.com/dudu/archive/2011/03/29/entity_framework_cross_database_query_fact.html

核心思路 欺骗SQL 利用创建同义词去实现

六.ef4.1执行连接查询?什么时候执行左连接? 什么时候执行内连接? ef 根据什么去判断?

当我们做多表查询时  用Include 强制加载 或用 select 去查询时  发现生成的SQL语句 有时是左连接  有时是inner join。

其实EF是根据我们实体类的连接字段 是否可空来判断的~比如外键 studentID

public  Nullable<int> StudentID { get; set; }

是否可空 就会造成 是 left join 还是 inner join~~

补充下~~ 有个朋友说 这个设为空了 依然执行的是内连接啊~

注意看下你的关系那块  也要设为可空 用这个   HasOptional 而不要用  HasRequired ~~

当你的外键可以为空时 用 HasOptional  否则用 HasRequired

这块也会决定你是内链接 还是 左连接~~

七.新手使用ef4.1 常见的一些报错信息

1.执行命令定义时出错

出现这个错的原因有很多  数据库语句错误 我们可以先通过监测SQL 语句是否发送到数据库 然后执行这条SQL语句 看看是否有问题

造成这个错的原因 还有可能是 连接对象一直被占用 因为EF有延迟加载 只是select时 并没有真正去数据库执行

我们可以先把前面的查询语句 tolist等  再去执行下面的操作

2.

System.Data.Edm.EdmEntityType: : EntityType“Enrollment”未定义键。请为该 EntityType 定义键。
System.Data.Edm.EdmEntitySet: EntityType: EntitySet ?Enrollments? 基于未定义键的类型 ?Enrollment?。
遇到这种情况 尝试给主键加上[Key]

3.更新条目错误

依然检测数据库语句 是否有外键约束导致插入错误等

4.LINQ to Entities 不识别方法“System.String ToString(System.String)”因此该方法无法转换为存储表达式

或者不识别其他方法......类似于这样的错误

因为SQL里没有这样的方法 所以无法转换成SQL语句  SqlClient 和Linq Provider没有实现那个方法对应的SQL,所以会提示不支持

解决办法:

1. 把要转换的值提前转换好 而不要再 linq 或拉姆达表示里写 这样的转换语。

就是把变量 .ToString()  提到外面声明个变量  然后在拉姆达表达式里 直接使用这个变量

2. 转换成 Enumerable

IEnumerable是直接执行方法 ,而不调用Provider来转成其它的方式

这样会把数据库里的查询出来 然后在内存里操作  所以数据库量大时 效率会低~

八.ef4.1使用datatable

datatable 在有的时候是非常有用的 例如 做报表等  因为我们不可能为每个报表建一个 实体类 这样比较麻烦

这个时候返回datatable  则比较有用

写一个扩展方法

   /// <summary>
       /// EF SQL 语句返回 dataTable
       /// </summary>
       /// <param name="db"></param>
       /// <param name="sql"></param>
       /// <param name="parameters"></param>
       /// <returns></returns>
       public static DataTable SqlQueryForDataTatable(this Database db,
                string sql,
                SqlParameter[] parameters)
       {

           SqlConnection conn = new System.Data.SqlClient.SqlConnection();
           conn.ConnectionString = db.Connection.ConnectionString;
           if (conn.State != ConnectionState.Open)
           {
               conn.Open();
           }
           SqlCommand cmd = new SqlCommand();
           cmd.Connection = conn;
           cmd.CommandText = sql;

           if (parameters.Length>0)
           {
               foreach (var item in parameters)
               {
                   cmd.Parameters.Add(item);
               }
           }

           SqlDataAdapter adapter = new SqlDataAdapter(cmd);
           DataTable table = new DataTable();
           adapter.Fill(table);
           return table;
       }

调用如下

   protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            GridView1.DataSource = GetDataTable();
            GridView1.DataBind();
        }
    }

    public DataTable GetDataTable()
    {
        GardenHotelContext context = new GardenHotelContext();
        int LanType = 0;
        int state = 0;
        SqlParameter[] sqlparams=new SqlParameter[2];
        sqlparams[0]=new SqlParameter("LanType",LanType);
        sqlparams[1]=new SqlParameter("state",state);
        DataTable DataTable = context.Database.SqlQueryForDataTatable("select LeaveName,LeaveEmail from LeaveInfo where [email protected] and [email protected]", sqlparams);
        return DataTable;

    }

再分享一种方法  先上调用效果  利用返回的var 匿名类型  这样就无需声明实体类了

  public DataTable GetDataTable2()
    {
        GardenHotelContext context = new GardenHotelContext();

        var list = (from l in context.LeaveInfoes
                   group l by l.LanType into g
                   select new
                   {
                       g.Key,
                       num = g.Count()
                   }).ToList();

        return PubClass.ListToDataTable(list);

    }

核心方法 反射调用

      #region  反射List To DataTable

        /// <summary>
        /// 将集合类转换成DataTable
        /// </summary>
        /// <param name="list">集合</param>
        /// <returns></returns>
        public static DataTable ListToDataTable(IList list)
        {
            DataTable result = new DataTable();
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    result.Columns.Add(pi.Name, pi.PropertyType);
                }

                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        object obj = pi.GetValue(list[i], null);
                        tempList.Add(obj);
                    }
                    object[] array = tempList.ToArray();
                    result.LoadDataRow(array, true);
                }
            }
            return result;
        }  

        #endregion

当然 解决这个问题 也可以用 上面的 动态视图的方法去解决~

九.总结

目前上面这几个问题 被问的比较多~ 写个文章 以后就不用再回答类似的问题啦~

我的解决方法不是最好的  有更好的解决办法 欢迎回复~期待你的精彩回复!

如果大家还遇到什么EF4.1的问题 或者 mvc3上的问题 都欢迎留言 ~我尽力帮大家

时间: 2024-11-05 18:37:16

MVC3+EF4.1学习系列(十一)----EF4.1常见的问题解决的相关文章

MVC3+EF4.1学习系列(九)-----EF4.1其他的一些技巧的使用

上节通过一系列重构 简单的项目就实现了 不过还有些EF的功能没有讲 这节就通过项目 讲讲EF其他的功能与技巧 一.直接执行SQL语句 通常来讲 EF 不用写SQL语句的  但是 在有些场合  比如对生成的SQL语句 觉得不满意 要做优化  或者做报表统计时 要写很变态的SQL语句 再或者 批量操作等   这个时候 使用ORM的弱点就显露了出来 但是 做为优秀的ORM框架  EF 是支持原生态的SQL的   这里面 提供了三种方法 1. DbSet.SqlQuery   有跟踪状态的查询  2. 

MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化

上篇文章中 我们已经创建了EF4.1基于code first的例子  有了数据库 并初始化了一些数据  今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建详细页 首先 我们先在控制器下 添加详细页的方法 因为这篇文章后面要介绍持久对象声明周期的变化 所以在这里先看下有哪些状态 EF里一共有这五中生命状态类型 其实 看名字我们可以大概猜测出个一二三来~~  游离的 未改变的  新添加的  已删除的 修改的  但是是怎么变化的能 我们在后面的代码中实践与

MVC3+EF4.1学习系列(一)-------创建EF4.1 code first的第一个实例

基于EF4.1 code first 简单的CRUD  园子中已经有很多了 ~~ 真不想再写这个了 可是为了做一个完整的小demo 从开始 到后面的一些简单重构 还是决定认真把这个写出来 争取写些别人没写到的东西~~ 好了 开始~~ 这次要做的是个学校管理的demo(通俗些) 先建一个MVC3的应用程序  因为我们是code first 所以 开始创建实体类 一.创建Model 学生和学生成绩登记表是一对多的关系  一个学生可以有多次登记 (因为有多个课程)  一个课程也可以有多个登记   可以

MVC3+EF4.1学习系列(七)-----EF并发的处理

看这篇文章之前 推荐园子里的 这个文章已经有介绍了 而且写的很好~~ 可以先看下他的 再看我的 并发 1.悲观并发 简单的说 就是一个用户访问一条数据时 则把这个数据变为只读属性  把该数据变为独占 只有该用户释放了这条数据 其他用户才能修改 这期间如果该用户上个厕所 出去玩一圈 没有退出 则其他人都要等很久 很显然 这不是我们期望的效果  也不是这篇文章讨论的重点 2.乐观并发 乐观并发相对悲观并发,用户读取数据时不锁定数据.当一个用户更新数据时,系统将进行检查,查看该用户读取数据后其他用户是

MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式

通过上一篇的学习 我们把demo的各种关系终于搭建里起来 以及处理好了如何映射到数据库等问题 但是 只是搭建好了关系 问题还远没有解决 这篇就来写如何查找导航属性 和查找导航属性的几种方式 已经跟踪生成的SQL来检测是否满意 通过这节学习 来明白什么时候用哪个~~ 一.三种加载 1.延迟加载 这是原文中的图 大家可以去看下  我模仿上面的做了个测试  出现了  已有打开的与此 Command 相关联的 DataReader,必须首先将它关闭. 我的解决办法是    var departments

MVC3+EF4.1学习系列(八)-----利用Repository and Unit of Work重构项目

项目最基础的东西已经结束了,但是现在我们的项目还不健全  不利于测试 重复性代码多   层与层之间耦合性高  不利于扩展等问题.今天的这章 主要就是解决这些问题的.再解决这些问题时,自己也产生了很多疑问,理解的也并不是很透彻 ,希望我的疑问能在这里得到解答~~ 一.模式介绍 1.Repository 在<企业架构模式>中,通过用来访问领域对象的一个类似集合的接口,在领域与数据映射层之间进行协调.还有请大家参考这个  P OF EAA详细介绍 然后说下我对这个的感觉和疑问   怎么都觉得这个Re

MVC3+EF4.1学习系列(十)----MVC+EF处理树形结构

通过前几篇文章 我们处理了 一对一, 一对多,多对多关系 很好的发挥了ORM框架的做用 但是 少说了一种 树形结构的处理, 而这种树形关系 我们也经常遇到,常见的N级类别的处理, 以及经常有数据与类别挂钩.今天主要写下EF处理树形结构以及 MVC如何展示树形结构. 前面几篇的例子 一直用的是一个例子,内容是连贯的.这篇是完全单独的~ 先来说下工作中会遇到的常见场景 针对这几个场景来处理~ 1.类别 a.类别可以有无限级别 b.类别的最末端 不确定是第几级 某个节点 可以到二级 其他的节点 有可能

Quartz.NET学习系列(十一)--- Quartz.NET持久化及客户端服务器模式

持久化         Quartz.NET如果不进行数据库相关配置,则默认的执行模式为内存模式,优点是执行速度快,确定就是数据无法存储,宕机了需要重新开始. 持久化只需要做如下配置(以SQLServer为例) NameValueCollection properties = new NameValueCollection(); //存储类型 properties["quartz.jobStore.type"] = "Quartz.Impl.AdoJobStore.JobSt

hadoop 入门学习系列十一----hue安装

1. hue整体架构 2.解压hue 3.安装依赖 yum install gmp-devel 4. 编译 make apps 5.修改hue的配置文件 desktop/conf/hue.ini 6.启动hue 7.Hue与hadoop集成 在hadoop的core-site.xml里增加配置 <property> <name>hadoop.proxyuser.hue.hosts</name> <value>*</value> </prop