一、修改數據 其實修改涉及的內容挺多的,是相對於其他操作來說比較繁瑣。也是本文的重頭戲。 雖然都是基礎內容,但是也是值得細細品味的。 1、最簡單直接的修改數據就是從資料庫里檢索出數據修改相應的欄位即可 數據表: Code: using (var db = new ApplicationDbConte
一、修改數據
其實修改涉及的內容挺多的,是相對於其他操作來說比較繁瑣。也是本文的重頭戲。
雖然都是基礎內容,但是也是值得細細品味的。
1、最簡單直接的修改數據就是從資料庫里檢索出數據修改相應的欄位即可
數據表:
Code:
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two old_entity = db.Twos.Single(t => t.Text == "90");
old_entity.Text = "update";
db.SaveChanges();
}
結果:
2、直接更新不需要檢索出數據
數據表:
Code:
通過修改實體的狀態來實現
ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
結果:
這個方式有個不好地方,圖中很明顯的標註出來了,就是會一股腦更新全部欄位,沒有值就被更新成NULL。
3、指定欄位更新
數據表:
Code:
修改實體狀態為Unchanged.
設置指定屬性的狀態為修改
ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
db.Entry(entity).State = EntityState.Unchanged;
db.Entry(entity).Property("Text").IsModified = true;
db.SaveChanges();
}
結果:
4、禁用驗證實體的有效性
有時我們在更新時有些欄位是不更新的,但是這些欄位又可能會有一些驗證特性,比如不可以為空,這樣我們在保存時會因實體驗證不通過而報錯。
實體:
Uu是必須的,不可為空
public class MyFirst
{
public int MyFirstId { get; set; }
public string Text { get; set; }
[Required]
public string Uu { get; set; }
}
Code:
ApplicationDbContext.MyFirst entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
db.Entry(entity).State = EntityState.Unchanged;
db.Entry(entity).Property("Text").IsModified = true;
db.SaveChanges();
}
結果:
因沒通過Uu的特性的驗證而報錯了,我們只更新了Text,沒有給Uu賦值,但是Uu又是不可以為空的
只要我們在保存前取消這種驗證就可以了,在保存後恢復驗證
修改後的Code:
ApplicationDbContext.MyFirst entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
db.Entry(entity).State = EntityState.Unchanged;
db.Entry(entity).Property("Text").IsModified = true;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
db.Configuration.ValidateOnSaveEnabled = true;
}
數據表:
結果:
5、在不同的上下文中更新數據
情況一
Code:
ApplicationDbContext.Two entity;
using(var db1=new ApplicationDbContext())
{
entity = db1.Twos.Single(m => m.Text == "90");
}
entity.Text = "update";
using (var db = new ApplicationDbContext())
{
DbEntityEntry entry = db.Entry(entity);
entry.State = EntityState.Modified;
db.SaveChanges();
}
在這種場景下更新有一個問題是,數據會全部更新,並不是我們指定的Text更新,原因是不在一個上下文中,在另一個上下文中沒有上一個上下文的狀態,所以更新時沒法判定就全部更新了。
數據圖:
在db1獲取數據時設置一個斷點,手動修改資料庫後的數據表:
結果數據:
會發現數據都被更新了,對比第二張圖
情況二
Code:
ApplicationDbContext.Two entity;
using(var db1=new ApplicationDbContext())
{
entity = db1.Twos.Single(m => m.Text == "90");
}
entity.Text = "update";
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
DbEntityEntry entry = db.Entry(entity);
entry.State = EntityState.Modified;
db.SaveChanges();
}
在這種場景下,與上面的區別是第二個上下文也檢索了數據,這種情況就是報錯,原因就是同一個上下文中不能出現主鍵值相同的實體。db檢索數據時存在了一個實體在上下文中,又要把db1檢索出的實體添加到db上下文中,一但主鍵值相同就會報錯
解決上述情況:
關鍵點是entry.CurrentValues.SetValues(entity);設置當前上下文實體的值。
Code:
ApplicationDbContext.Two entity;
using(var db1=new ApplicationDbContext())
{
entity = db1.Twos.Single(m => m.Text == "90");
}
entity.Text = "update";
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
DbEntityEntry entry = db.Entry(entity1);
entry.CurrentValues.SetValues(entity);
db.SaveChanges();
}
數據圖:
在db獲取數據時設置一個斷點,手動修改資料庫後的數據表:
結果數據:
會發現只有指定的數據更新了,對比第二張圖
6、同一個上下文中有實體存在的情況下用外部數據更新
Code:
ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
DbEntityEntry entry = db.Entry(entity);
entry.State = EntityState.Modified;
db.SaveChanges();
}
會報錯,原因和上面情況一樣,上下文中出現了主鍵一樣的多個實體,本來有一個實體了,又載入了一個主鍵一樣的實體,就報錯了。
用上述方法解決試試看
Code:
ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
DbEntityEntry entry = db.Entry(entity1);
entry.CurrentValues.SetValues(entity);
db.SaveChanges();
}
沒有報錯,成功更新數據,但是問題是全部數據都被更新,不是我們指定的數據更新
結果數據:
嘗試使用指定屬性更新:
結果你會發現數據沒有發生任何變化,原因是entry.State = EntityState.Unchanged;把ntry.CurrentValues.SetValues(entity);改變得值有還原回去了。
ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
DbEntityEntry entry = db.Entry(entity1);
entry.CurrentValues.SetValues(entity);
entry.State = EntityState.Unchanged;
entry.Property("Text").IsModified = true;
db.SaveChanges();
}
解決上述問題:
如果要解決上述問題應該使用ObjectContext的ObjectStateEntry設置當前值,狀態,以及指定修改的屬性
Code:
ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");
ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;
ObjectStateEntry entry = objectContext.ObjectStateManager.GetObjectStateEntry(entity1);
entry.ApplyCurrentValues(entity);
entry.ChangeState(EntityState.Unchanged);
entry.SetModifiedProperty("Text");
db.SaveChanges();
}
結果數據:
對上上述更新方式做一個封裝
public static class Test
{
//指定更新
public static void Update<TEntity>(this DbContext dbcontext,
Expression<Func<TEntity, object>> propertyExpression,
params TEntity[] entities) where TEntity : EntityBase
{
if (propertyExpression == null)
{
throw new ArgumentException("propertyExpression");
}
if (entities == null)
{
throw new ArgumentException("entities");
}
ReadOnlyCollection<MemberInfo> memberInfos = ((dynamic)propertyExpression.Body).Members;
foreach (TEntity entity in entities)
{
try
{
DbEntityEntry<TEntity> entry = dbcontext.Entry(entity);
entry.State = EntityState.Unchanged;
foreach (var memberInfo in memberInfos)
{
entry.Property(memberInfo.Name).IsModified = true;
}
}
catch
{
TEntity originalEntity = dbcontext.Set<TEntity>().Single(m => m.Id == entity.Id);
ObjectContext objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;
ObjectStateEntry objectEntry = objectContext.ObjectStateManager.GetObjectStateEntry(originalEntity);
objectEntry.ApplyCurrentValues(entity);
objectEntry.ChangeState(EntityState.Unchanged);
foreach (var memberInfo in memberInfos)
{
objectEntry.SetModifiedProperty(memberInfo.Name);
}
}
}
}
//提交保存
public static int SaveChanges(this DbContext dbContext, bool validateOnSaveEnabled)
{
bool isReturn = dbContext.Configuration.ValidateOnSaveEnabled != validateOnSaveEnabled;
try
{
dbContext.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabled;
return dbContext.SaveChanges();
}
finally
{
if (isReturn)
{
dbContext.Configuration.ValidateOnSaveEnabled = !validateOnSaveEnabled;
}
}
}
//全部更新
public static void Update1<TEntity>(this DbContext dbContext, params TEntity[] entities) where TEntity : EntityBase
{
if (dbContext == null) throw new ArgumentException("dbContext");
if (entities == null) throw new ArgumentException("entities");
foreach(TEntity entity in entities)
{
DbSet<TEntity> dbSet = dbContext.Set<TEntity>();
try
{
DbEntityEntry<TEntity> entry = dbContext.Entry(entity);
if (entry.State == EntityState.Detached)
{
entry.State = EntityState.Modified;
}
}
catch
{
TEntity oldEntity = dbSet.Find(entity.Id);
dbContext.Entry(oldEntity).CurrentValues.SetValues(entity);
}
}
}
}
public class EntityBase
{
public int Id { get; set; }
}
public class Three : EntityBase
{
public string Text { get; set; }
public string Uu { get; set; }
}
封裝後的使用實例:
pplicationDbContext.Three entity= new ApplicationDbContext.Three() { Id = 1, Text = "update" };
using (var db = new ApplicationDbContext())
{
ApplicationDbContext.Three entity1 = db.Threes.Single(m => m.Text == "90");
db.Update<ApplicationDbContext.Three>(m => new { m.Text }, entity);
db.SaveChanges();
}
至此更新部分已經全部完畢
Ps:其實擴展方法update有個坑,就是一但出現併發時就會報錯走catch,而其實不是想要的結果,這是個忽略的地方,併發應該拋出錯誤,用catch是忽略了併發的情況...額...
二、添加數據
簡單明瞭沒有啥好說的
Code:
ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Text = "我哦哦哦" };
using (var db = new ApplicationDbContext())
{
db.Threes.Add(entity);
db.SaveChanges();
}
數據圖:
三、刪除數據
簡單明瞭沒啥好說的
通過Attach把實體載入到上下文,關鍵點就是實體要存在於上下文中
Code:
ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id=2 };
using (var db = new ApplicationDbContext())
{
db.Threes.Attach(entity);
db.Threes.Remove(entity);
db.SaveChanges();
}
Code:
ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id = 3 };
using (var db = new ApplicationDbContext())
{
db.Entry(entity).State = EntityState.Deleted;
db.SaveChanges();
}
四、查詢
1、簡單查詢
int[] scores = { 90, 71, 82, 93, 75, 82 };
IEnumerable<int> scoreQuery =
from score in scores
where score > 80
orderby score descending
select score;
foreach (int testScore in scoreQuery)
{
Console.WriteLine(testScore);
}
//輸出結果:93 90 82 82
2、分組查詢
var queryLastNames =
from student in students
group student by student.LastName into newGroup
orderby newGroup.Key
select newGroup;
3、內聯查詢
var query = from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.FirstName, PetName = pet.Name };
4、分組連接
結果是:一個名字對應一個集合
var query = from person in people
join pet in pets on person equals pet.Owner into gj
select new { OwnerName = person.FirstName, Pets = gj };
5、外聯查詢
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
6、在查詢中處理null
var query1 =
from c in categories
where c != null
join p in products on c.ID equals
(p == null ? null : p.CategoryID)
select new { Category = c.Name, Name = p.Name };
var query =
from o in db.Orders
join e in db.Employees
on o.EmployeeID equals (int?)e.EmployeeID
select new { o.OrderID, e.FirstName };
7、在查詢中處理異常
IEnumerable<int> dataSource;
try
{
dataSource = GetData();
}
catch (InvalidOperationException)
{
Console.WriteLine("Invalid operation");
goto Exit;
}
var query = from i in dataSource
select i * i;
foreach (var i in query)
Console.WriteLine(i.ToString());
Exit:
Console.WriteLine("Press any key to exit");
string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };
var exceptionDemoQuery =
from file in files
let n = SomeMethodThatMightThrow(file)
select n;
try
{
foreach (var item in exceptionDemoQuery)
{
Console.WriteLine("Processing {0}", item);
}
catch (InvalidOperationException e)
{
Console.WriteLine(e.Message);
}
更多關於查詢請查考MSDN,裡面很詳細
https://msdn.microsoft.com/zh-cn/library/bb384065.aspx