日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值?

發布時間:2023/12/18 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

之前的兩篇有關EF4.1的文章反響不錯,感謝大家的支持!想體驗EF4.1的新功能?RTW版本已經發布啦http://www.microsoft.com/downloads/en/details.aspx?FamilyID=b41c728e-9b4f-4331-a1a8-537d16c6acdf&displaylang=en???

Entity Framework 4.1 DbContext使用記之一——如何查找實體? DbSet.Find函數的使用與實現

Entity Framework 4.1 DbContext使用記之二——如何玩轉本地實體? DbSet.Local屬性的使用與實現

?

今天的主題是如何玩轉EF4.1中實體的屬性。實體的屬性其實是我們使用EF來訪問和修改實體的關鍵。在EF以前版本中,如果我們一般會直接訪問對象的屬性,比如得到PersonID大于100的所有Person實體的ID和Name:

using?(var?context?=?new?MyContext())
{
????var?people?
=?context.People.Where(p?=>?p.PersonID?>?100);
????
for?(var?p?in?people)
????{
????????Console.WriteLine(
"ID:?{0},?Name:{1}",?p.PersonID,?p.Name);
????}

}?

但是如果要得到ObjectContext所track的實體屬性的OriginalValues(原始值)和CurrentValues(當前值),則不是很方便。

?

而在EF4.1中,由于我們可以使用DbContext.Entry()或DbContext.Entry<T>()來得到DbEntityEntry或DbEntityEntry<T>對象。通過DbEntityEntry (DbEntityEntry<T>)的OriginalValues和CurrentValues屬性,我們可以方便地得到相應的屬性集合(DbPropertyValues)。通過DbEntityEntry (DbEntityEntry<T>)的Property(Property<T>)方法得到DbPropertyEntry(DbPropertyEntry<T>)之后,我們也能通過相應的OriginalValue和CurrentValue屬性得到單個屬性的原始值和當前值。感覺有點繞?看看下面的這些例子應該就簡單明了多了!?

using?(var?context?=?new?MyDbContext())
{
????
//?有關Find方法,請看EF4.1系列博文一
????var?person?=?context.People.Find(1);

????
//?得到Person.Name屬性的當前值
????string?currentName?=?context.Entry(person).Property(p?=>?p.Name).CurrentValue;

????
//?設置Person.Name屬性的當前值
????context.Entry(person).Property(p?=>?p.Name).CurrentValue?=?"Michael";

????
//?通過string值"Name"來獲得DbPropertyEntry,而非通過Lambda?Expression
????object?currentName2?=?context.Entry(person).Property("Name").CurrentValue;
}

?

再來看看如何得到實體的所有屬性的OriginalValue(原始值),CurrentValue(當前值)和DatabaseValue(數據庫值)吧:

using?(var?context?=?new?MyDbContext())
{
????var?person?
=?context.People.Find(1);

????
//?改變對應的實體的Name屬性
????person.Name?=?"Michael";

????
//?改變對應屬性的數據庫值
????context.Database.ExecuteSqlCommand("update?Person set?Name?=?'Lingzhi'?where PersonID =?1");

????
//?輸出對應實體所有屬性的當前值,原始值和數據庫值
????Console.WriteLine("Current?values:");
????PrintValues(context.Entry(person).CurrentValues);

????Console.WriteLine(
"\nOriginal?values:");
????PrintValues(context.Entry(person).OriginalValues);

????Console.WriteLine(
"\nDatabase?values:");
????PrintValues(context.Entry(person).GetDatabaseValues());
}

這里用到的PrintValues函數實現如下:

public?void?PrintValues(DbPropertyValues?values)
{
????
foreach?(var?propertyName?in?values.PropertyNames)
????{
????????Console.WriteLine(
"Property?{0}?has?value?{1}",
??????????????????????????propertyName,?values[propertyName]);
????}
}

這里具體的輸出大家就當小練習吧,呵呵。

?

下面再為大家介紹兩個我個人認為比較cool的小功能:

1) 設置多層的復雜類型的屬性。

例如,Person實體含有Address復雜類型屬性(Complex - type),Address又含有City這一string類型屬性,那么我們可以這樣來獲得City這一屬性的當前值:

//?使用Lambda?Expression
string?city?=?context.Entry(person).Property(p?=>?p.Address.City).CurrentValue;

//?使用string類型的屬性表達
object?city?=?context.Entry(person).Property("Address.City").CurrentValue;

這里層次的次數其實沒有限制,可以一直點下去的。:) ? EF的內部實現也是使用遞歸調用的方式,之后會有詳細的介紹。?

?

2) 克隆含有實體屬性當期值,原始值或數據庫值的對象。

我們可以使用DbPropertyValues.ToObject()方法來克隆將DbPropertyValues中相應的屬性和值變成對象。

using?(var?context?=?new?MyDbContext())
{
????var?person?
=?context.People.Find(1);
????var?clonedPerson?
=?context.Entry(person).GetDatabaseValues().ToObject();

}?

這里克隆到的對象不是實體類,也不被DbContext所跟蹤。但這樣的對象在處理數據庫并發等問題時會很有用。


又到了探尋以上介紹的功能的內部實現的時候啦!我們還是照例使用.NET Reflector來查看EntityFramework.dll。 大家可以打開Reflector和我一起來做個簡單的分析。


首先是從DbContext.Entry方法得到DbEntityEntry。Entry方法通過調用DbEntityEntry internal的構造函數DbEntityEntry(InternalEntityEntry internalEntityEntry)來創建一個DbEntityEntry對象。這里的InternalEntityEntry又是通過DbContext.InternalContext和先前傳入Entry函數的實體對象來生成的。

public?InternalEntityEntry(InternalContext?internalContext,?object?entity)
{
????
this._internalContext?=?internalContext;
????
this._entity?=?entity;
????
?? ?//?ObjectContextTypeCache應該是EF內部保存的靜態的類型緩存,用于查找實體類型
????this._entityType?=?ObjectContextTypeCache.GetObjectType(this._entity.GetType());
????
?? ?//?InternalContext.GetStateEntry內部則調用了ObjectStateManager.TryGetObjectStateEntry方法
????this._stateEntry?=?this._internalContext.GetStateEntry(entity);
????
if?(this._stateEntry?==?null)
????{
????????
this._internalContext.Set(this._entityType).InternalSet.Initialize();
????}
}

?

下面來看看DbEntityEntry.CurrentValues/OriginalValues。CurrentValues和OriginalValues屬性都是DbPropertyValues類型的。DbPropertyValues可以被理解為對于一個實體或復雜類型所有屬性信息的集合。我們通過PropertyNames屬性拿到其所有屬性的名字,通過GetValue或SetValues方法得到或設置屬性值。還能通過我們之前討論的ToObject方法來克隆一個有用與對應實體或復雜類型對象一樣屬性值的對象。演示一下如何使用DbPropertyValues.SetValuesF方法:

using?(var?context?=?new?MyDbContext())
{
????var?person?
=?context.People.Find(1);
????var?person1?
=?new?Person?{?PersonID?=?1,?Name?=?"Michael"?};
????var?person2?
=?new?Person?{?PersonID?=?1,?Name?=?"Lingzhi"?};

????var?entry?
=?context.Entry(person);
????
????
//?這里直接將擁有相應屬性值的實體對象直接賦給SetValues方法,直接對person實體的CurrentValues和OriginalValues進行賦值
????entry.CurrentValues.SetValues(person1);
????entry.OriginalValues.SetValues(person2);
}

?

這里SetValues內部首先調用了DbHelpers.GetPropertyGetters方法。DbHelpers是System.Data.Entity.Internal命名空間下Internal的類,包含了許多靜態的輔助方法。這里的GetPropertyGetters顧名思義就是得到屬性Getter方法delegate的集合,內部當然是通過PropertyInfo以及.NET Reflection來完成。有了這個Getter方法delegate的集合,我們就能方便地拿到傳入SetValues方法的對象的所有屬性值了,最后則按照所得到的屬性值來進行賦值。

?

接著我們再來看看如何從DbEntityEntry.Property得到DbPropertyEntry。我們可以傳遞兩種property的表達方式給DbEntityEntry.Property方法:1) Lambda Expression ? 2) string類型的property表示。先來說說1),在將Lambda Expression解析為對應property時,EF使用了輔助靜態方法DbHelpers.ParsePropertySelector,ParsePropertySelector又調用了另一靜態輔助方法DbHelpers.TryParsePath。具體算法在這里就不做深入解析,簡單說這個TryParsePath方法就是遞歸地將Lambda Expression所表示的property層層深入地獲取到,例如像這樣的Lambda Expression:person => person.Address.City最后就變為"Address.City"。在解析完畢之后,ParsePropertySelector其實也是將Lambda Expression變成了string類型的property表示。自然,EF此時就調用了第二個接受string類型的property表示的DbEntityEntry.Property重載。DbEntityEntry.Property(string)在經過了一系列其他的內部調用之后,到了System.Data.Entity.Internal.InternalEntityEntry.Property(...):

private?InternalPropertyEntry?Property(InternalPropertyEntry?parentProperty,?string?propertyName,?IList<string>?properties,?Type?requestedType,?bool?requireComplex)
{
????
bool?flag?=?properties.Count?>?1;
????Type?type?
=?flag???typeof(object)?:?requestedType;
????Type?declaringType?
=?(parentProperty?!=?null)???parentProperty.EntryMetadata.ElementType?:?this.EntityType;
????PropertyEntryMetadata?metadata?
=?this.ValidateAndGetPropertyMetadata(properties[0],?declaringType,?type);
????
if?((metadata?==?null)?||?((flag?||?requireComplex)?&&?!metadata.IsComplex))
????{
????????
if?(flag)
????????{
????????????
throw?Error.DbEntityEntry_DottedPartNotComplex(properties[0],?propertyName,?declaringType.Name);
????????}
????????
throw?(requireComplex???Error.DbEntityEntry_NotAComplexProperty(properties[0],?declaringType.Name)?:?Error.DbEntityEntry_NotAScalarProperty(properties[0],?declaringType.Name));
????}
????InternalPropertyEntry?entry?
=?(InternalPropertyEntry)?metadata.CreateMemberEntry(this,?parentProperty);
????
if?(!flag)
????{
????????
return?entry;
????}
????
return?this.Property(entry,?propertyName,?properties.Skip<string>(1).ToList<string>(),?requestedType,?requireComplex);

}?

從標黃的語句中不難發現,這個函數也是遞歸調用,并且將多層的property一一解析。?System.Data.Entity.Internal.InternalEntityEntry.Property函數返回InternalPropertyEntry類型的對象。這個對象又被返回給DbPropertyEntry.Create方法,Create方法又調用了InternalPropertyEntry.CreateDbMemberEntry:

?

public?override?DbMemberEntry<TEntity,?TProperty>?CreateDbMemberEntry<TEntity,?TProperty>()?where?TEntity:?class
{
????
if?(!this.EntryMetadata.IsComplex)
????{
????????
return?new?DbPropertyEntry<TEntity,?TProperty>(this);
????}
????
return?new?DbComplexPropertyEntry<TEntity,?TProperty>(this);
}

?

這里的邏輯很簡單,將property分成一般的屬性或復雜類型的屬性,分別處理之。分析到這里,大家應該也發現了DbPropertyEntry中大部分信息都保存在其內部的InternalPropertyEntry對象里。這樣的設計在解析EntityFramework.dll時,我們會經常看到。

?

呼!這篇文章不是一口氣寫完的了,這幾天挺忙的,不過每天添幾筆,可能思路有些混亂,大家見諒,哈哈!還是那句話,希望對您學習EF有點幫助吧!

?

PS1:這里為大家帶來一個好消息:微軟一站式實例代碼庫(Microsoft All-In-One Code Framework)即日起正式遷移至MSDN代碼庫了,新的平臺會幫您更輕松地解決開發難題、節省更多時間、獲得更友好的用戶體驗。本人作為這個項目的元老,見到我們已擁有600多個經典的代碼實例,甚感欣慰啊!??更詳細信息,請看http://msdn.microsoft.com/zh-cn/hh124104.aspx?ocid=ban-f-cn-loc-OC201104-MSDN

之后我將盡力為大家帶來更多有關EF的代碼實例以及相關的介紹!



PS2:同事開發了一個很cool的MSDN論壇桌面小工具,絕對給力!歡迎使用!(我也出了不少力啊)


也歡迎到MSDN中文論壇ADO.NET與LINQ論壇來提問EF的問題啊,可以試試直接報我的名字Michael Sun,哈哈!

?

如需轉發請注明原文出處,謝謝:?http://www.cnblogs.com/LingzhiSun/archive/2011/04/13/EF41_WokingWithProperties.html

轉載于:https://www.cnblogs.com/LingzhiSun/archive/2011/04/13/EF41_WokingWithProperties.html

總結

以上是生活随笔為你收集整理的Entity Framework 4.1 DbContext使用记之三——如何玩转实体的属性值?的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。