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
2.执行返回值的存储过程
先上存储过程
CREATE PROCEDURE [dbo].[ProSelectCount]
@StuId int
AS
BEGIN
select COUNT(*) from Enrollment where StudentID=@StuId
END
一个简单的查询数量
这里用sqlQuery 执行访问 数据库 因为需要提供返回类型 而我们返回的是int 所以先得到int的类型
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 韋 给的帮助~~
SqlQueryForDynamic的扩展方法 public static class DatabaseExtensions { public static IEnumerable SqlQueryForDynamic(this Database db, string sql, params object[] parameters) { IDbConnection defaultConn = new System.Data.SqlClient.SqlConnection(); return SqlQueryForDynamicOtherDB(db, sql, defaultConn, parameters); } public static IEnumerable SqlQueryForDynamicOtherDB(this Database db, string sql, IDbConnection conn, params object[] parameters) { conn.ConnectionString = db.Connection.ConnectionString; if (conn.State != ConnectionState.Open) { conn.Open(); } IDbCommand cmd = conn.CreateCommand(); cmd.CommandText = sql; IDataReader dataReader = cmd.ExecuteReader(); if (!dataReader.Read()) { return null; //无结果返回Null } #region 构建动态字段 TypeBuilder builder = DatabaseExtensions.CreateTypeBuilder( "EF_DynamicModelAssembly", "DynamicModule", "DynamicType"); int fieldCount = dataReader.FieldCount; for (int i = 0; i < fieldCount; i++) { //dic.Add(i, dataReader.GetName(i)); //Type type = dataReader.GetFieldType(i); DatabaseExtensions.CreateAutoImplementedProperty( builder, dataReader.GetName(i), dataReader.GetFieldType(i)); } #endregion dataReader.Close(); dataReader.Dispose(); cmd.Dispose(); conn.Close(); conn.Dispose(); Type returnType = builder.CreateType(); if (parameters != null) { return db.SqlQuery(returnType, sql, parameters); } else { return db.SqlQuery(returnType, sql); } } public static TypeBuilder CreateTypeBuilder(string assemblyName, string moduleName, string typeName) { TypeBuilder typeBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName(assemblyName), AssemblyBuilderAccess.Run).DefineDynamicModule(moduleName).DefineType(typeName, TypeAttributes.Public); typeBuilder.DefineDefaultConstructor(MethodAttributes.Public); return typeBuilder; } public static void CreateAutoImplementedProperty( TypeBuilder builder, string propertyName, Type propertyType) { const string PrivateFieldPrefix = "m_"; const string GetterPrefix = "get_"; const string SetterPrefix = "set_"; // Generate the field. FieldBuilder fieldBuilder = builder.DefineField( string.Concat( PrivateFieldPrefix, propertyName), propertyType, FieldAttributes.Private); // Generate the property PropertyBuilder propertyBuilder = builder.DefineProperty( propertyName, System.Reflection.PropertyAttributes.HasDefault, propertyType, null); // Property getter and setter attributes. MethodAttributes propertyMethodAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; // Define the getter method. MethodBuilder getterMethod = builder.DefineMethod( string.Concat( GetterPrefix, propertyName), propertyMethodAttributes, propertyType, Type.EmptyTypes); // Emit the IL code. // ldarg.0 // ldfld,_field // ret ILGenerator getterILCode = getterMethod.GetILGenerator(); getterILCode.Emit(OpCodes.Ldarg_0); getterILCode.Emit(OpCodes.Ldfld, fieldBuilder); getterILCode.Emit(OpCodes.Ret); // Define the setter method. MethodBuilder setterMethod = builder.DefineMethod( string.Concat(SetterPrefix, propertyName), propertyMethodAttributes, null, new Type[] { propertyType }); // Emit the IL code. // ldarg.0 // ldarg.1 // stfld,_field // ret ILGenerator setterILCode = setterMethod.GetILGenerator(); setterILCode.Emit(OpCodes.Ldarg_0); setterILCode.Emit(OpCodes.Ldarg_1); setterILCode.Emit(OpCodes.Stfld, fieldBuilder); setterILCode.Emit(OpCodes.Ret); propertyBuilder.SetGetMethod(getterMethod); propertyBuilder.SetSetMethod(setterMethod); } }
四.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