это то, что я в конце концов использовал

я есть проект WCF с множеством детей. У меня есть бизнес-уровень и уровень доступа к данным, на уровне доступа к данным у меня есть репозитории, которые извлекаются и сохраняются в моей базе данных. Я понимаю, что EF создает и уничтожает DataContext по мере необходимости. Например, допустим, у меня есть сущность Person и сущность Book (это не мое приложение, а просто попытка проиллюстрировать проблему).

Предположим, лицо выглядит следующим образом.

Person
  string Name
  vitual ICollection<Book> Books

С книгой может быть что-то вроде этого

Book
 string Title
 Person PersonLending

Теперь в моем BLL я хочу прочитать таблицу person и затем назначить книгу этому человеку, но этот человек уже существует в базе данных, поэтому BLL вызывает хранилище для объекта person.

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 в таблице. Насколько я понимаю, это вызвано тем, что первый контекст разрушен, а второй контекст не знает, что Человек уже существует.

У меня есть два вопроса, я думаю.

Какова лучшая практика для обработки DataContext в WCF? Должен ли быть только один текстовый текст, передаваемый из класса в класс и обратно в репозитории.Или есть способ сделать это сохранить.

Я попытался установить EntityState на Без изменений на Персоне, но, похоже, это не работает.

Редактировать:

Я изменил вещи, чтобы создать новый DataContext для каждого запроса (AfterReceiveRequest и BeforeSendReply).

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

    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());
            }
        }    
    }

Initializer

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: В случае, если кто-то задается вопросом, моя фабрика данных просто имеет эти два метода

  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)

Ваш ответ на вопрос