1、修改數據數據庫
其實修改涉及的內容挺多的,是相對於其餘操做來講比較繁瑣。也是本文的重頭戲。併發
雖然都是基礎內容,可是也是值得細細品味的。ui
1、最簡單直接的修改數據就是從數據庫裏檢索出數據修改相應的字段便可this
數據表:spa
Code:3d
using (var db = new ApplicationDbContext())blog
{get
ApplicationDbContext.Two old_entity = db.Twos.Single(t => t.Text == "90");string
old_entity.Text = "update";it
db.SaveChanges();
}
結果:
二、直接更新不須要檢索出數據
數據表:
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。
三、指定字段更新
數據表:
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();
}
結果:
四、禁用驗證明體的有效性
有時咱們在更新時有些字段是不更新的,可是這些字段又可能會有一些驗證特性,好比不能夠爲空,這樣咱們在保存時會因實體驗證不經過而報錯。
實體:
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;
}
數據表:
結果:
五、在不一樣的上下文中更新數據
狀況一
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獲取數據時設置一個斷點,手動修改數據庫後的數據表:
結果數據:
會發現只有指定的數據更新了,對比第二張圖
六、同一個上下文中有實體存在的狀況下用外部數據更新
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是忽略了併發的狀況...額...
2、添加數據
簡單明瞭沒有啥好說的
Code:
ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Text = "我哦哦哦" };
using (var db = new ApplicationDbContext())
{
db.Threes.Add(entity);
db.SaveChanges();
}
數據圖:
3、刪除數據
簡單明瞭沒啥好說的
經過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();
}
4、查詢
一、簡單查詢
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
二、分組查詢
var queryLastNames =
from student in students
group student by student.LastName into newGroup
orderby newGroup.Key
select newGroup;
三、內聯查詢
var query = from person in people
join pet in pets on person equals pet.Owner
select new { OwnerName = person.FirstName, PetName = pet.Name };
四、分組鏈接
結果是:一個名字對應一個集合
var query = from person in people
join pet in pets on person equals pet.Owner into gj
select new { OwnerName = person.FirstName, Pets = gj };
五、外聯查詢
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) };
六、在查詢中處理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 };
七、在查詢中處理異常
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