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 int
AS
BEGIN Select Student.* from Enrollment,Student
where Enrollment.StudentID=Student.StudentID
and Enrollment.StudentID=@StudentID END GO

执行存储过程的方法 是用直接执行sql的方式 我在我的文章第九篇 有过详细的介绍~大家可以先去看下
执行表的存储过程 其实是非常强大的 延迟加载 等都有体现 博客园的陆老师已经写了 写的非常清楚了~我这里就不再写了 大家可以去他那看下 提供个连接~
2.执行返回值的存储过程
先上存储过程
CREATE PROCEDURE [dbo].[ProSelectCount]
@StuId int
AS
BEGIN
select COUNT(*) from Enrollment where StudentID=@StuId
END
一个简单的查询数量
这里用sqlQuery 执行访问 数据库 因为需要提供返回类型 而我们返回的是int 所以先得到int的类型
3.执行增删改

CREATE PROCEDURE [dbo].[ProDel]
@stuId int,
@courseId int
AS
BEGIN DELETE FROM [WLFSchool].[dbo].[Enrollment]
where StudentID=@stuId and CourseID=@courseId 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 韋 给的帮助~~
四.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 LanType=@LanType and State=@State", 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上的问题 都欢迎留言 ~我尽力帮大家
MVC3+EF4.1学习系列(十一)----EF4.1常见的问题解决的更多相关文章
- MVC3+EF4.1学习系列(九)-----EF4.1其他的一些技巧的使用
上节通过一系列重构 简单的项目就实现了 不过还有些EF的功能没有讲 这节就通过项目 讲讲EF其他的功能与技巧 一.直接执行SQL语句 通常来讲 EF 不用写SQL语句的 但是 在有些场合 比如对生 ...
- MVC3+EF4.1学习系列(一)-------创建EF4.1 code first的第一个实例
基于EF4.1 code first 简单的CRUD 园子中已经有很多了 ~~ 真不想再写这个了 可是为了做一个完整的小demo 从开始 到后面的一些简单重构 还是决定认真把这个写出来 争取写些别人 ...
- MVC3+EF4.1学习系列(二)-------基础的增删改查和持久对象的生命周期变化
上篇文章中 我们已经创建了EF4.1基于code first的例子 有了数据库 并初始化了一些数据 今天这里写基础的增删改查和持久对象的生命周期变化 学习下原文先把运行好的原图贴来上~~ 一.创建 ...
- MVC3+EF4.1学习系列(五)----- EF查找导航属性的几种方式
文章索引和简介 通过上一篇的学习 我们把demo的各种关系终于搭建里起来 以及处理好了如何映射到数据库等问题 但是 只是搭建好了关系 问题还远没有解决 这篇就来写如何查找导航属性 和查找导航属性的几种 ...
- MVC3+EF4.1学习系列(七)-----EF并发的处理
看这篇文章之前 推荐园子里的 这个文章已经有介绍了 而且写的很好~~ 可以先看下他的 再看我的 并发 1.悲观并发 简单的说 就是一个用户访问一条数据时 则把这个数据变为只读属性 把该数据变为独占 ...
- MVC3+EF4.1学习系列(六)-----导航属性数据更新的处理
通过上一篇的学习 我们已经知道怎么查询关系 这篇就来说说怎么导航属性数据更新时的处理 以及EF又会为我们生成哪些SQL~ 老规矩 先看下今天的图 添加和修改页面基本就是这样 这节的内容相对简单~~ 主 ...
- MVC3+EF4.1学习系列(三)-----排序 刷选 以及分页
上篇文章 已经做出了基本的增删改查 但这远远不足以应付实际的项目 今天讲下实际项目中 肯定会有的 排序 刷选 以及分页. 重点想多写点分页的 毕竟这个是任何时候都要有的 而且 我会尽量把这个 ...
- MVC3+EF4.1学习系列(四)----- ORM关系的处理
上篇文章 终于把基础的一些操作写完了 但是这些都是单表的处理 而EF做为一个ORM框架 就必须点说说对于关系的处理 处理好关系 才能灵活的运用EF 关于关系的处理 一般就是 一对一 一对多 ...
- MVC3+EF4.1学习系列(十)----MVC+EF处理树形结构
通过前几篇文章 我们处理了 一对一, 一对多,多对多关系 很好的发挥了ORM框架的做用 但是 少说了一种 树形结构的处理, 而这种树形关系 我们也经常遇到,常见的N级类别的处理, 以及经常有数据与类别 ...
随机推荐
- Cracking the Coding Interview 第二章
2.2 链表中倒数第k个结点 输入一个链表,输出该链表中倒数第k个结点. 思路:快慢指针(error: 判断是否有可行解,否则返回null, while, if 后加空格) /* public cla ...
- 网络爬虫之定向爬虫:爬取当当网2015年图书销售排行榜信息(Crawler)
做了个爬虫,爬取当当网--2015年图书销售排行榜 TOP500 爬取的基本思想是:通过浏览网页,列出你所想要获取的信息,然后通过浏览网页的源码和检查(这里用的是chrome)来获相关信息的节点,最后 ...
- java 异常的捕获及处理
在没有异常处理的程序中如果要回避异常,需要使用大量的判断语句,配合所想到的错误状况来捕捉程序中可能发生的错误.但是这样势必会导致程序运行效率降低.java异常处理机制具有易于使用,可自定义异常类,处理 ...
- python 访问数据库
commit() 提交rollback() 回滚 cursor用来执行命令的方法:callproc(self, procname, args):用来执行存储过程,接收的参数为存储过程名和参数列表,返回 ...
- Scala 控制结构
Scala内建的控制结构屈指可数,仅有if, while, for, match, try和函数调用而已. 几乎所有的Scala控制结构都会产生某个值(while和 do while虽然不能产生有意义 ...
- bat脚本-set(setlocal enabledelayedexpansion) 学习
设置本地为延迟扩展.其实也就是:延迟变量,全称延迟环境变量扩展. 事件一: @echo off set a=4 set a=5&echo %a% pause 解说:为什么是4而不是5呢?在ec ...
- Photoshop定义画笔选区为空的原因
定义画笔预设时,选择选区后需填充黑色,否则将出现选区为空的提示
- 5、范围标签<fieldset></fieldset>
<fieldset style="border:0;border:1px solid red;"> <legend style="background- ...
- 原 iOS深入学习(Block全面分析)http://my.oschina.net/leejan97/blog/268536
原 iOS深入学习(Block全面分析) 发表于1年前(2014-05-24 16:45) 阅读(26949) | 评论(14) 39人收藏此文章, 我要收藏 赞21 12月12日北京OSC源创会 ...
- mysql 创建用户与授权、修改密码
mysql版本:5.6.35 1.创建用户 #foo表示你要建立的用户名,后面的123表示密码, #localhost限制在固定地址localhost登陆 CREATE USER foo@localh ...