AppBox升級進行時 - Entity Framework的增刪改查

三生石上(FineUI控制元件)發表於2013-09-09

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/)。

 

 

 

相關文章