AppBox升级进行时 - Entity Framework的增删改查
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理、职称管理、部门管理、角色管理、角色权限管理等模块。
Entity Framework新增数据
以新增用户为例,作为对比,先来看下使用Subsonic的代码:
using (TransactionScope scope = new TransactionScope()) { XUser item = new XUser(); item.Name = tbxName.Text.Trim(); item.ChineseName = tbxRealName.Text.Trim(); item.Gender = ddlGender.SelectedValue; item.CompanyEmail = tbxEmail.Text.Trim(); item.PersonalEmail = tbxPersonalEmail.Text.Trim(); item.OfficePhone = tbxOfficePhone.Text.Trim(); item.OfficePhoneExt = tbxOfficePhoneExt.Text.Trim(); item.HomePhone = tbxHomePhone.Text.Trim(); item.CellPhone = tbxCellPhone.Text.Trim(); item.Remark = tbxRemark.Text.Trim(); item.Enabled = cbxEnabled.Checked; //item.DeptId = Convert.ToInt32(ddlDept.SelectedValue); item.CreateTime = DateTime.Now; item.Save(); // 添加所有角色 if (!String.IsNullOrEmpty(hfSelectedRole.Text)) { XRoleUserCollection roleUsers = new XRoleUserCollection(); foreach (string roleIdStr in hfSelectedRole.Text.Split(',')) { int id = Convert.ToInt32(roleIdStr); XRoleUser roleUser = new XRoleUser(); roleUser.RoleId = id; roleUser.UserId = item.Id; roleUsers.Add(roleUser); } roleUsers.SaveAll(); } scope.Complete(); }
由于需要操作两张表,所以使用了事务(TransactionScope),并在两个数据库操作全部完成之后调用 scope.Complete。
使用Entity Framework的代码无需使用事务,EF会正确的处理表关联,代码如下:
User item = new User(); item.Name = tbxName.Text.Trim(); item.Password = PasswordUtil.CreateDbPassword(tbxPassword.Text.Trim()); item.ChineseName = tbxRealName.Text.Trim(); item.Gender = ddlGender.SelectedValue; item.CompanyEmail = tbxCompanyEmail.Text.Trim(); item.Email = tbxEmail.Text.Trim(); item.OfficePhone = tbxOfficePhone.Text.Trim(); item.OfficePhoneExt = tbxOfficePhoneExt.Text.Trim(); item.HomePhone = tbxHomePhone.Text.Trim(); item.CellPhone = tbxCellPhone.Text.Trim(); item.Remark = tbxRemark.Text.Trim(); item.Enabled = cbxEnabled.Checked; item.CreateTime = DateTime.Now; // 添加所有角色 if (!String.IsNullOrEmpty(hfSelectedRole.Text)) { int[] roleIDs = StringUtil.GetIntArrayFromString(hfSelectedRole.Text); item.Roles = DB.Roles.Where(r => roleIDs.Contains(r.ID)).ToList(); } DB.Users.Add(item); DB.SaveChanges();
上面的代码虽说可以正常运行,但是在设置用户角色列表时(item.Roles)进行了数据库查询,而这次查询可以通过Attach方法避免,更新后的版本:
User item = new User(); item.Name = tbxName.Text.Trim(); item.Password = PasswordUtil.CreateDbPassword(tbxPassword.Text.Trim()); item.ChineseName = tbxRealName.Text.Trim(); item.Gender = ddlGender.SelectedValue; item.CompanyEmail = tbxCompanyEmail.Text.Trim(); item.Email = tbxEmail.Text.Trim(); item.OfficePhone = tbxOfficePhone.Text.Trim(); item.OfficePhoneExt = tbxOfficePhoneExt.Text.Trim(); item.HomePhone = tbxHomePhone.Text.Trim(); item.CellPhone = tbxCellPhone.Text.Trim(); item.Remark = tbxRemark.Text.Trim(); item.Enabled = cbxEnabled.Checked; item.CreateTime = DateTime.Now; // 添加所有角色 if (!String.IsNullOrEmpty(hfSelectedRole.Text)) { int[] roleIDs = StringUtil.GetIntArrayFromString(hfSelectedRole.Text); item.Roles = new List<Role>(); foreach (int roleID in roleIDs) { Role role = new Role { ID = roleID }; DB.Roles.Attach(role); item.Roles.Add(role); } } DB.Users.Add(item); DB.SaveChanges();
根据微软官方文档对Attach的解释:http://msdn.microsoft.com/en-us/data/jj592676
If you have an entity that you know already exists in the database but which is not currently being tracked by the context then you can tell the context to track the entity using the Attach method on DbSet. The entity will be in the Unchanged state in the context.
Attach的数据已经存在数据库中,但是还没有被加载到EF上下文中 ,Attach后的实体处于Unchanged的状态。后面我们会有详细的博文讲解Attach,到时你会发现这里对Attach的用法其实还是有点问题的。
Entity Framework删除数据
最为对比,先来看下使用Subsonic如何删除一组用户:
new Delete().From<XUser>() .Where(XUser.IdColumn).In(ids) .Execute();
而使用EF的代码并不那么直观,因为在EF中删除数据之间要先把数据加载到EF上下文中,如下所示:
DB.Users.Where(u => ids.Contains(u.UserID)).ToList().ForEach(u => DB.Users.Remove(u)); DB.SaveChanges();
那么有没有办法像Subsonic一样删除数据呢?其实办法早就有了:https://github.com/loresoft/EntityFramework.Extended
我们需要在项目中添加这个库,然后在页面添加如下引用:
using EntityFramework.Extensions;
现在的删除代码就简单多了:
DB.Users.Delete(u => ids.Contains(u.UserID));
Entity Framework修改数据
修改某个用户的属性,使用Subsonic的代码:
XUserCollection users = new Select().From<XUser>() .Where(XUser.IdColumn).In(ids) .ExecuteAsCollection<XUserCollection>(); foreach (XUser user in users) { user.Enabled = enabled; } users.BatchSave();
使用EF的代码也是类似的,先将需要修改数据的加载到内存中,然后修改:
DB.Users.Where(u => ids.Contains(u.UserID)).ToList().ForEach(u => u.Enabled = enabled); DB.SaveChanges();
使用 EntityFramework.Extended 后,代码就更加简单了,并且减少了数据库连接次数:
DB.Users.Update(u => ids.Contains(u.UserID), u => new User { Enabled = enabled });
Entity Framework查询数据(数据库分页)
查询用户列表,并进行数据库分页的Subsonic代码如下所示:
SqlQuery q = new Select().From<XUser>(); q.Where("1").IsEqualTo("1"); // 在职务名称中搜索 string searchText = ttbSearchMessage.Text.Trim(); if (!String.IsNullOrEmpty(searchText)) { q.And(XUser.NameColumn).ContainsString(searchText); } // 过滤启用状态 if (rblEnableStatus.SelectedValue != "all") { q.And(XUser.EnabledColumn).IsEqualTo(rblEnableStatus.SelectedValue == "enabled" ? true : false); } // 在查询添加之后,排序和分页之前获取总记录数 // Grid1总共有多少条记录 Grid1.RecordCount = q.GetRecordCount(); // 排列 q.OrderBys.Add(GetSortExpression(Grid1, XUser.Schema)); // 数据库分页 q.Paged(Grid1.PageIndex + 1, Grid1.PageSize); XUserCollection items = q.ExecuteAsCollection<XUserCollection>(); Grid1.DataSource = items; Grid1.DataBind();
使用Entity Framework的代码也很简单:
var q = DB.Users.Include(u => u.Dept); // 在用户名称中搜索 string searchText = ttbSearchMessage.Text.Trim(); if (!String.IsNullOrEmpty(searchText)) { q = q.Where(u => u.Name.Contains(searchText) || u.ChineseName.Contains(searchText) || u.EnglishName.Contains(searchText)); } // 过滤启用状态 if (rblEnableStatus.SelectedValue != "all") { q = q.Where(u => u.Enabled == (rblEnableStatus.SelectedValue == "enabled" ? true : false)); } // 在查询添加之后,排序和分页之前获取总记录数 Grid1.RecordCount = q.Count(); // 排列 q = q.OrderBy(u => u.Name); // 数据库分页 q = q.Skip(Grid1.PageIndex * Grid1.PageSize).Take(Grid1.PageSize); Grid1.DataSource = q; Grid1.DataBind();
和Subsonic的代码类似,首先添加Where查询条件,然后数据库查询获取总记录数(q.Count),之后进行排序,最后是数据库分页。
美中不足的是排序,Entity Framework的OrderBy默认不支持字符串表示的列名!
没关系,下个版本我们会介绍如何向OrderBy传递字符串参数。
下载或捐赠AppBox
1. AppBox v2.1 是免费软件,免费提供下载:http://fineui.com/bbs/forum.php?mod=viewthread&tid=3788
2. AppBox v3.0 是捐赠软件,你可以通过捐赠作者来获取AppBox v3.0的全部源代码(http://fineui.com/donate/)。