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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

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

Entity Framework 4.1 DbContext使用記之一——如何查找實體? DbSet.Find函數(shù)的使用與實現(xiàn)

Entity Framework 4.1 DbContext使用記之二——如何玩轉(zhuǎn)本地實體? DbSet.Local屬性的使用與實現(xiàn)

?

今天的主題是如何玩轉(zhuǎn)EF4.1中實體的屬性。實體的屬性其實是我們使用EF來訪問和修改實體的關(guān)鍵。在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(當(dāng)前值),則不是很方便。

?

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

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

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

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

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

?

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

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

????
//?改變對應(yīng)的實體的Name屬性
????person.Name?=?"Michael";

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

????
//?輸出對應(yīng)實體所有屬性的當(dāng)前值,原始值和數(shù)據(jù)庫值
????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函數(shù)實現(xiàn)如下:

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

這里具體的輸出大家就當(dāng)小練習(xí)吧,呵呵。

?

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

1) 設(shè)置多層的復(fù)雜類型的屬性。

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

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

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

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

?

2) 克隆含有實體屬性當(dāng)期值,原始值或數(shù)據(jù)庫值的對象。

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

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

}?

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


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


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

public?InternalEntityEntry(InternalContext?internalContext,?object?entity)
{
????
this._internalContext?=?internalContext;
????
this._entity?=?entity;
????
?? ?//?ObjectContextTypeCache應(yīng)該是EF內(nèi)部保存的靜態(tài)的類型緩存,用于查找實體類型
????this._entityType?=?ObjectContextTypeCache.GetObjectType(this._entity.GetType());
????
?? ?//?InternalContext.GetStateEntry內(nèi)部則調(diào)用了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可以被理解為對于一個實體或復(fù)雜類型所有屬性信息的集合。我們通過PropertyNames屬性拿到其所有屬性的名字,通過GetValue或SetValues方法得到或設(shè)置屬性值。還能通過我們之前討論的ToObject方法來克隆一個有用與對應(yīng)實體或復(fù)雜類型對象一樣屬性值的對象。演示一下如何使用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);
????
????
//?這里直接將擁有相應(yīng)屬性值的實體對象直接賦給SetValues方法,直接對person實體的CurrentValues和OriginalValues進行賦值
????entry.CurrentValues.SetValues(person1);
????entry.OriginalValues.SetValues(person2);
}

?

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

?

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

}?

從標(biāo)黃的語句中不難發(fā)現(xiàn),這個函數(shù)也是遞歸調(diào)用,并且將多層的property一一解析。?System.Data.Entity.Internal.InternalEntityEntry.Property函數(shù)返回InternalPropertyEntry類型的對象。這個對象又被返回給DbPropertyEntry.Create方法,Create方法又調(diào)用了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分成一般的屬性或復(fù)雜類型的屬性,分別處理之。分析到這里,大家應(yīng)該也發(fā)現(xiàn)了DbPropertyEntry中大部分信息都保存在其內(nèi)部的InternalPropertyEntry對象里。這樣的設(shè)計在解析EntityFramework.dll時,我們會經(jīng)常看到。

?

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

?

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

之后我將盡力為大家?guī)砀嘤嘘P(guān)EF的代碼實例以及相關(guān)的介紹!



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


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

?

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

轉(zhuǎn)載于:https://www.cnblogs.com/LingzhiSun/archive/2011/04/13/EF41_WokingWithProperties.html

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。