У меня есть небольшой обзор кода для вас, потому что ваш пример кода пугает меня.
Вы, наверное, много читали о модных моделях проектирования и многоуровневых архитектурах, и вы начали использовать их сами. К сожалению, вы пропустили главное. Что это за чертовщина?
service.repository._context.XXX
Почему вы беспокоитесь о каком-либо слое обслуживания или уровне хранилища, если они не инкапсулируют свою логику? Почему вы выставляете репозиторий на сервис? Никто не должен знать о внутренней реализации сервиса? Еще хуже, почему вы выставляете контекст в хранилище? Это испортило весь смысл хранилища!
Существует множество поддерживающих правил для написания высококачественного объектно-ориентированного кода. Одно из этих правил называется Закон Деметры . Вам не нужно следовать каждому правилу, вам также не нужно все время следовать правилам, но в случае многоуровневой архитектуры этот закон является обязательным.
Если у вас есть три уровня A -> B -> C, уровень A может вызывать методы на уровне B, но он не знает о C и не может достичь своих методов. Если это возможно, это не новый уровень, но это тот же уровень, что и B, и уровень A не должен вызывать его через B, он может вызывать его напрямую.
В вашем примере вы только что выставили D на A, потому что A - текущий слой, B - service
, C - repository
и D - context
.
Еще один момент о вашем коде. Есть хорошо известные соглашения об именах. Эти соглашения касаются не того, что мне нравится, а вам это нравится, а того факта, что используемая вами среда строго следует этим соглашениям, поэтому использование другого соглашения для смешивания соглашения об именах с соглашением об именах платформы сделает ваш код грязным.
Извините, если бы это был только пример кода, чтобы сделать структуру вашего кода понятной. Мне просто нужно было описать, насколько этот код неправильный.
Теперь к вашей настоящей проблеме. Метод, на который вы ссылались из соответствующего вопроса, не будет работать в вашем случае. Я думаю, что это будет работать, только если вы загрузите подписку из базы данных. Причина в том, что указанный метод использует EntityKey
(внутренне или напрямую) для получения объекта из контекста, но у вашего нового объекта еще нет ключа объекта. Я ожидаю, что вызов TryGetObjectStateEntry
для вашей сущности всегда вернет Detached
. Ключ сущности создается во время присоединения или вам нужно создать его вручную.
Если вы хотите какой-нибудь IsAttachedTo
метод, попробуйте это:
public bool IsAttachedTo<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.Any(e => e.Id == entity.Id);
}
И убедитесь, что ваша сущность реализует вспомогательный интерфейс
public interface IEntity
{
int Id { get; }
}
Но для того, чтобы отсоединить подключенную сущность, вам понадобится:
public T GetAttached<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.SingleOrDefault(e => e.Id == entity.Id);
}
Вам придется отсоединить экземпляр, возвращенный этим методом.
В любом случае, я бы начал думать, зачем вам это нужно, во-первых, потому что похоже, что ваша архитектура имеет другую неправильную концепцию. Почему вы не используете прикрепленные объекты напрямую? Если вы не используете их, почему вы даже держите контекст с ними?