2011-06-09 118 views
1

我有一個WCF項目與一個實體有很多孩子。我有一個業務層和一個數據訪問層,在數據訪問層中,我有存儲庫,可以檢索並保存到我的數據庫。我對EF的理解是,您可以在需要時創建和銷燬DataContext。舉個例子,假設我有一個Person實體和一個Book實體(這不是我的應用程序,只是爲了試圖說明問題)。實體框架4.1代碼優先與N層保存雙重

假設人看起來如下。

​​

的書,也許是這樣的

Book 
string Title 
Person PersonLending 

現在我BLL我想讀的人表,然後分配給一本書的人,但是這個人已經存在於數據庫中,所以BLL調用一個人實體的存儲庫。

var person = repository.GetPerson("John Doe"); 

我的存儲庫中有此代碼。

using(var context = new MyContext()) 
{ 
    return (from p in context.Person 
      where p.Name == person 
      select p).FirstOrDefault()); 
} 

現在在BLL中,我創建一本新書並將其分配給它。

var book = new Book(); 
book.PersonLending = person; 
book.Title = "New Book"; 

repository.SaveBook(); 

最後在存儲庫中,我嘗試保存該書。

using(var context = new MyContext()) 
{ 
    context.Book.Add(book); 
    context.SaveChanges(); 
} 

現在發生什麼是我得到表中的兩個人行。我的理解是,這是由第一個上下文被破壞引起的,第二個上下文不知道Person已經存在。

我想我有兩個問題。

  1. 在WCF中處理DataContext的最佳做法是什麼?是否應該只有一個從一個類傳遞到另一個類的數據上下文並存入存儲庫。
  2. 或者有沒有辦法讓這個保存。

我已經嘗試設置EntityState在人身上不變,但它似乎沒有工作。

編輯:

我已經改變了事情,創造每個請求一個新的DataContext(AfterReceiveRequest和BeforeSendReply)。

public class EFWcfDataContextAttribute : Attribute, IServiceBehavior 
{ 
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase){} 

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters){} 

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) 
    { 
     foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers) 
     { 
      foreach (var endpoint in channelDispatcher.Endpoints) 
      { 
       endpoint.DispatchRuntime.MessageInspectors.Add(new EFWcfDataContextInitializer()); 
       //endpoint.DispatchRuntime.InstanceContextInitializers.Add(new EFWcfDataContextInitializer()); 
      } 
     }  
    } 

初始化程序

public class EFWcfDataContextInitializer : IDispatchMessageInspector 
{ 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
     instanceContext.Extensions.Add(new EFWcfDataContextExtension(new MyDataContext())); 
     return null; 
    } 

    public void BeforeSendReply(ref Message reply, object correlationState) 
    { 
     WcfDataContextFactory.Dispose(); 
    } 
} 

和擴展

public class EFWcfDataContextExtension : IExtension<InstanceContext> 
{ 
    public ICoreDataContext DataContext { get; private set; } 

    public EFWcfDataContextExtension(ICoreDataContext coreDataContext) 
    { 
     if(DataContext != null) 
      throw new Exception("context is not null"); 

     DataContext = coreDataContext; 
    } 

    public void Attach(InstanceContext owner){} 

    public void Detach(InstanceContext owner) {} 
} 

這似乎給了一個全新的問題。我通過調用OperationContext.Current.InstanceContext.Extensions.Find()。DataContext來獲取當前上下文,但現在看來這兩個上下文相互影響。在同一個請求中,第一個將返回空記錄,第二個將成功。它們都在獨特的會話中,並且當它們都被創建時它們都是空的並且被創建爲新的DataContext。當我在第一次檢查Database.Connection屬性時關閉它,並手動嘗試打開它會產生更多錯誤。我真的認爲這會解決問題。

我也試着用IContractBehaviour做這個,結果相同。所以要麼我做錯了什麼,要麼我錯過了一些明顯的東西。

PS:我試着將狀態設置爲「未更改」,然後再進行原始發佈。 PPS:如果有人想知道,我的DataFactory只是有這兩種方法

public static void Dispose() 
    { 
     ICoreDataContext coreDataContext = OperationContext.Current.InstanceContext.Extensions.Find<EFWcfDataContextExtension>().DataContext; 
     coreDataContext.Dispose(); 
     coreDataContext = null; 
    } 

    public static ICoreDataContext GetCurrentContext() 
    { 
     var context = OperationContext.Current.InstanceContext.Extensions.Find<EFWcfDataContextExtension>().DataContext; 
     if (context != null) 
     { 
      if (context.Database.Connection.State == ConnectionState.Closed) 
       context.Database.Connection.Open(); 
     } 

     return context; 
    } 

回答

1

你的理解是完全正確的。一旦將數據傳回服務,新的上下文既不知道BookPerson。在Book上調用Add的作用是將對象圖中的每個未知實體標記爲Added。這是分離場景的非常大的問題。

該解決方案未共享上下文這是處理該問題的最糟糕的方式,因爲它引入了a lot of other problems,最後它仍然不起作用。每次服務呼叫使用新的上下文。

試試這個:

using(var context = new MyContext()) 
{ 
    context.Book.Attach(book); 
    context.Entry(book).State = EntityState.Added; 
    context.SaveChanges(); 
} 

或本:

using(var context = new MyContext()) 
{ 
    context.Book.Add(book); 
    context.Entry(book.PersonLending).State = EntityState.Unchanged; 
    context.SaveChanges(); 
} 

這個問題more complex,一旦你開始與關係的變化發送更復雜的對象圖。您將首先加載對象圖並將更改合併到附加實體中。

+0

要將此標記爲已回答,儘管它沒有直接回答問題,但它確實指向了正確的方向。 http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/是我最終使用的 – Dirk 2011-06-15 07:40:30

相關問題