2013-02-10 94 views
3

我嘗試分離group類型的實體。爲什麼我的EF分離不夠?

Actucally我把它保存在我的緩存,並響應客戶端之前取下它一會兒。

在接下來的請求,我從緩存和重新attch一個新的ObjectContext的group

但是我得到An entity object cannot be referenced by multiple instances of IEntityChangeTracker

我知道附上包括所有相關實體,但分離不。在那裏,我必須分離所有相關的實體。

我是什麼,我缺少的分離?

這裏是我的實體hirarchy:

public partial class App 
{ 
    public App() 
    { 
     this.Pairs = new HashSet<Pair>(); 
    } 

    public string AppName { get; set; } 
    public System.Guid AppGuid { get; set; } 
    public string ClientAppID { get; set; } 
    public bool IsDeleted { get; set; } 
    public Nullable<System.DateTime> CreatedDate { get; set; } 
    public Nullable<System.DateTime> UpdatedDate { get; set; } 

    public virtual AppsData AppsData { get; set; } 
    public virtual ICollection<Pair> Pairs { get; set; } 
} 


public partial class AppsData 
{ 
    public System.Guid AppGuid { get; set; } 
    public string Url { get; set; } 
    public string DisplayName { get; set; } 
    public string AppDesc { get; set; } 
    public string PrivacyPolicyUrl { get; set; } 
    public string TermsOfUseUrl { get; set; } 
    public string LocalizationKey { get; set; } 
    public string Compatibility { get; set; } 
    public bool HiddenApp { get; set; } 
    public bool IsExperimental { get; set; } 

    public virtual App App { get; set; } 
} 

public partial class Browser 
{ 
    public Browser() 
    { 
     this.BrowserVersions = new HashSet<BrowserVersion>(); 
    } 

    public int BrowserID { get; set; } 
    public string BrowserName { get; set; } 
    public string BrowserCode { get; set; } 

    public virtual ICollection<BrowserVersion> BrowserVersions { get; set; } 
} 

public partial class BrowserVersion 
{ 
    public BrowserVersion() 
    { 
     this.BrowserVerToCriterias = new HashSet<BrowserVerToCriteria>(); 
    } 

    public System.Guid BrowserVersionID { get; set; } 
    public int BrowserID { get; set; } 
    public string Version { get; set; } 
    public System.DateTime CreatedDate { get; set; } 
    public System.DateTime UpdatedDate { get; set; } 
    public Nullable<int> Group_Id { get; set; } 

    public virtual Browser Browser { get; set; } 
    public virtual ICollection<BrowserVerToCriteria> BrowserVerToCriterias { get; set; } 
} 

public partial class BrowserVerToCriteria 
{ 
    public System.Guid CriteriaID { get; set; } 
    public System.Guid BrowserVersionID { get; set; } 
    public string ConditionBrowserVersion { get; set; } 

    public virtual BrowserVersion BrowserVersion { get; set; } 
    public virtual Criterion Criterion { get; set; } 
} 

public partial class CommonConfig 
{ 
    public int ID { get; set; } 
    public string NAME { get; set; } 
    public string VALUE { get; set; } 
    public System.DateTime CREATED_DATE { get; set; } 
    public System.DateTime UPDATED_DATE { get; set; } 
    public byte GROUP_ID { get; set; } 
    public string DESCRIPTION { get; set; } 
} 

public partial class Country 
{ 
    public Country() 
    { 
     this.Criteria = new HashSet<Criterion>(); 
     this.Criteria1 = new HashSet<Criterion>(); 
    } 

    public int CountryID { get; set; } 
    public string CountryCode { get; set; } 
    public string CountryName { get; set; } 

    public virtual ICollection<Criterion> Criteria { get; set; } 
    public virtual ICollection<Criterion> Criteria1 { get; set; } 
} 

    public Criterion() 
    { 
     this.BrowserVerToCriterias = new HashSet<BrowserVerToCriteria>(); 
     this.Countries = new HashSet<Country>(); 
     this.CountriesExceptions = new HashSet<Country>(); 
     this.Pairs = new HashSet<Pair>(); 
    } 

    public System.Guid CriteriaID { get; set; } 
    public string Domains { get; set; } 
    public System.DateTime CreatedDate { get; set; } 
    public System.DateTime UpdatedDate { get; set; } 
    public string DomainsExclude { get; set; } 

    public virtual ICollection<BrowserVerToCriteria> BrowserVerToCriterias { get; set; } 
    public virtual ICollection<Country> Countries { get; set; } 
    public virtual ICollection<Country> CountriesExceptions { get; set; } 
    public virtual ICollection<Pair> Pairs { get; set; } 
} 

public partial class CTID 
{ 
    public string CTID1 { get; set; } 
    public string AppVersion { get; set; } 
} 

public partial class CtidPgPastExistence 
{ 
    public string Ctid { get; set; } 
} 

public partial class Group 
{ 
    public Group() 
    { 
     this.Pairs = new HashSet<Pair>(); 
    } 

    public System.Guid GroupId { get; set; } 
    public int TestId { get; set; } 
    public int IdInTest { get; set; } 
    public bool WelcomeExperienceEnabledByDefault { get; set; } 

    public virtual MamConfiguration MamConfiguration { get; set; } 
    public virtual ICollection<Pair> Pairs { get; set; } 
} 

public partial class MamConfiguration 
{ 
    public MamConfiguration() 
    { 
     this.Groups = new HashSet<Group>(); 
     this.MamConfigurationCTIDs = new HashSet<MamConfigurationCTID>(); 
    } 

    public int TestID { get; set; } 
    public string TestName { get; set; } 
    public string Description { get; set; } 
    public int StatusId { get; set; } 
    public System.DateTime CreatedDate { get; set; } 
    public System.DateTime UpdatedDate { get; set; } 
    public bool IsProd { get; set; } 
    public int TestTraffic { get; set; } 

    public virtual ICollection<Group> Groups { get; set; } 
    public virtual MamConfigurationStatus MamConfigurationStatus { get; set; } 
    public virtual ICollection<MamConfigurationCTID> MamConfigurationCTIDs { get; set; } 
} 

public partial class MamConfigurationCTID 
{ 
    public int TestID { get; set; } 
    public string CTID { get; set; } 

    public virtual MamConfiguration MamConfiguration { get; set; } 
} 

public partial class MamConfigurationStatus 
{ 
    public MamConfigurationStatus() 
    { 
     this.MamConfigurations = new HashSet<MamConfiguration>(); 
    } 

    public int StatusId { get; set; } 
    public string Status { get; set; } 

    public virtual ICollection<MamConfiguration> MamConfigurations { get; set; } 
} 

public partial class Pair 
{ 
    public Pair() 
    { 
     this.Groups = new HashSet<Group>(); 
    } 

    public System.Guid PairID { get; set; } 
    public System.Guid CriteriaID { get; set; } 
    public System.Guid AppGuid { get; set; } 

    public virtual App App { get; set; } 
    public virtual Criterion Criterion { get; set; } 
    public virtual ICollection<Group> Groups { get; set; } 
} 

public partial class SettingsServicesConfig 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string URL { get; set; } 
    public int Interval { get; set; } 
    public System.DateTime UPDATED_DATE { get; set; } 
    public System.DateTime CREATED_DATE { get; set; } 
    public int GROUP_ID { get; set; } 
} 

這裏是我的分離功能:

public void Detach<T>(MaMDBEntities maMdbEntities, T item) where T : class, new() 
{ 
    switch (typeof (T).Name.ToLower()) 
    { 
     case "group": 
      { 
       var group = item as Group; 

       if (group == null) 
       { 
        mApplicationLogger.Error(string.Format("Couldn't cast item to type 'Group'")); 

        throw new InvalidCastException(string.Format("Couldn't cast item to type 'Group'")); 
       } 

       DetachState(maMdbEntities, group.MamConfiguration); 

       foreach (var pair in group.Pairs.ToList()) 
       { 
        DetachState(maMdbEntities, pair.App); 

        DetachState(maMdbEntities, pair.App.AppsData); 

        foreach (var country in pair.Criterion.Countries.ToList()) 
        { 
         DetachState(maMdbEntities, country); 
        } 

        foreach (var country in pair.Criterion.CountriesExceptions.ToList()) 
        { 
         DetachState(maMdbEntities, country); 
        } 


        foreach (var browserVerToCriterias in pair.Criterion.BrowserVerToCriterias.ToList()) 
        { 
         DetachState(maMdbEntities, browserVerToCriterias.BrowserVersion.Browser); 

         DetachState(maMdbEntities, browserVerToCriterias.BrowserVersion); 

         DetachState(maMdbEntities, browserVerToCriterias); 
        } 

               DetachState(maMdbEntities, pair.Criterion); 

        DetachState(maMdbEntities, pair); 

       } 

       break; 
      } 
    } 
    maMdbEntities.Entry(item).State = EntityState.Detached; 
} 

private static void DetachState(MaMDBEntities maMdbEntities, object item) 
{ 
    maMdbEntities.Entry(item).State = EntityState.Detached; 
} 
+0

錯誤消息會提示DbContext(MaMDBEntities?)的第二個實例在使用中。 – 2013-02-11 10:01:03

+0

MaMDBEntities是我的ObjectContext。AFAIK DBContext處於低級別(意味着在後面的edmx代碼中)。我不想分離(並且很早就使這些實體無效)。我怎樣才能檢查哪些仍然需要分離? – 2013-02-11 19:08:05

+0

@你可以看看'Aiston'的答案,你認爲這樣可以完全分離嗎?或者總是會有另外一個呃在上下文中反對我會錯過而不是分離? – 2013-02-11 22:20:50

回答

1

我認爲,你需要確保沒有殘留在實體您的背景,參考任何已被分離的內容。所以,如果說,別的引用對的脫管的實例,上下文會很高興地發現它,穿過它的導航性能,並添加了一大堆回來

,而不是設置國家財產你嘗試過:

((IObjectContextAdapter)maMdbEntities).ObjectContext.Detach(item); 

據說這是爲了分離,除了項目本身被分離到項目的任何鏈接。

編輯

好吧,讓我們看看「分離,以脫離該項目的任何鏈接...」,ObjectContext.Detach最終調用這個方法:

// System.Data.Objects.EntityEntry 
internal void Detach() 
    { 
    base.ValidateState(); 
    bool flag = false; 
    RelationshipManager relationshipManager = this._wrappedEntity.RelationshipManager; 
    flag = (base.State != EntityState.Added && this.IsOneEndOfSomeRelationship()); 
    this._cache.TransactionManager.BeginDetaching(); 
    try 
     { 
     relationshipManager.DetachEntityFromRelationships(base.State); 
     } 
    finally 
     { 
     this._cache.TransactionManager.EndDetaching(); 
     } 
    this.DetachRelationshipsEntries(relationshipManager); 
    IEntityWrapper wrappedEntity = this._wrappedEntity; 
    EntityKey entityKey = this._entityKey; 
    EntityState state = base.State; 
    if (flag) 
     { 
     this.DegradeEntry(); 
     } 
    else 
     { 
     this._wrappedEntity.ObjectStateEntry = null; 
     this._cache.ChangeState(this, base.State, EntityState.Detached); 
     } 
    if (state != EntityState.Added) 
     { 
     wrappedEntity.EntityKey = entityKey; 
     } 
    } 

DetachEntityFromRelationships打破所有的鏈接。 上ObjectContext.Detach的文件是不特定對撕裂的鏈接http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.detach.aspx下它並說「分開方法被調用後,系統將不再繼續指向這個對象的引用,它可以被垃圾收集器收集」 ,這意味着所有的LinkDescriptor也將被刪除。

至於你的第三個評論「你覺得IObjectContextAdapter將實現完全分離,或者總是會有在上下文中的其他對象,我會misss而不是分離?」這裏有兩件事。有對象的屬性和上下文用來跟蹤關係的LinkDescriptor。分離只是通過分離鏈接描述符來停止跟蹤對象的關係,它不會在關係的另一端分離對象。它也不會將這些屬性設置爲null,如果在分離後檢查該對象仍然會設置這些屬性。

這是最好的方法嗎?拆卸和重新連接很難正確。如果你需要分離並重新連接,我建議你將深度分離的rountines移到類中,而不是用一般的方法。

這就是說,你寫道:「在下一個請求中,我從緩存中獲取組......」「這導致我想知道兩次請求之間最長的時間是什麼?你能通過緩存來引入併發問題嗎?你是否在IIS中託管WCF服務?如果併發不會成爲問題,你可以使用IIS的緩存嗎?你可能不知道ObjectContext實例方法不是線程安全的

+0

1)你有什麼不同的建議來解決我的問題嗎? 2)這是我第一次看到分離根實體及其所有引用的方法。它可以在任何級別完成 - 不要背後的edmx代碼?除了項目本身之外,你是從哪裏看到「分離與被分離項目的鏈接? – 2013-02-11 19:12:11

+0

不知道如何解決我的問題? 1)深度手動克隆 - 意味着我將手動從EF分離。 2)使用IObjectContextAdapter與希望它將面向所有參考實體分離? 3)刪除我的緩存層4)其他? – 2013-02-11 22:19:13

+0

你認爲'IObjectContextAdapter'將啓用完全分離。或者在上下文中總會有其他的對象,我會錯過而不會分離? – 2013-02-11 22:21:11