Объект, осведомленная о объекте, в EF, чтобы избежать анемичной доменной модели
Вопрос
В рамках сущности можно ли сделать структуру вводить DBContext в каждый объект (объект), который прикреплен или извлекается из контекста?
Я парень из Nhibernate, и я знаю, что это возможно в NH, - извините, если это глупый вопрос в мире EF.
По сути, я хочу, чтобы некоторые из моих сущностей имели свойство типа DBContext, которое будет установлено в экземпляр контекста самой структурой, когда я ассоциирую объект с контекстом. В идеале такие классы будут отмечены интерфейсом маркера Icontextaware или чем -то подобным.
Причина, по которой я хочу это сделать, заключается в том, что на этот раз я хочу избежать анемичной доменной модели анти-паттерна. Я подумал, что если у меня есть объект, введенный в сущности, они смогут получить доступ к DB, что позволит мне реализовать запросы и более сложную логику сами внутри классов доменов. Если вы знаете другие способы достижения моей цели (особенно в контексте веб -приложения), пожалуйста, сделайте, но, пожалуйста, старайтесь избегать ответов, таких как «Вы не должны делать это, потому что». Спасибо!!!
Решение
Вы не должны делать этого, потому что вы хотите сохранить проблемы настойчивости от ваших объектов домена =)
Но если вам нужно, вы можете зацепить событие ObjectMaterialized, запущенное ObjectContext. В CTP5 вам нужно отменить свой DBContext, как в конструкторе для вашего DBContext:
((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized +=
this.ObjectContext_OnObjectMaterialized;
Затем реализуйте свою функцию objectcontext_onobjectmaterialized (отправитель объекта, ObjectMaterializedEventargs E). Через EventArgs вы сможете получить доступ к своему объекту, который только что материализовался. Оттуда вы можете установить свойство Poco ObjectContext/DBContext, которое должно быть либо публичным, либо внутренним.
Другие советы
Помимо связывания вашего домена с конкретной технологией устойчивости, существуют другие консервы с инъекцией контекста на этом уровне. Например, в чем время жизни в контексте, который вы вводите, и должен ли этот контекст всегда иметь одинаковую жизнь для каждой сущности?
Я понимаю, что вы хотите определить свои бизнес -методы на объектах, чтобы вы могли сказать customer.MakeCustomerPreferred
. Анкет Однако есть другие способы сделать это, без необходимости писать бизнес -логику на этом уровне в приложении ». Например, вы можете использовать деловые мероприятия. Вот пример:
public class Customer
{
public void MakeCustomerPreferred()
{
var e = new MakeCustomerPreferredEvent()
{
Customer = this
};
DomainEvents.Current.Handle(e);
}
}
public interface IDomainEvent { }
public interface IHandle<T> where T : IDomainEvent
{
void Handle(T instance);
}
public class MakeCustomerPreferredEvent : IDomainEvent
{
prop Customer Customer { get; set; }
}
А DomainEvents
Класс это окружающий контекст Это позволяет вам получить все обработчики для конкретного домена и выполнять их.
public class DomainEvents
{
public static DomainEvents Current = new DomainEvents();
public virtual void Handle<T>(T instance)
where T : IDomainEvent
{
var handlers =
YourIocContainer.GetAllInstances<IHandle<T>>();
foreach (var handler in handlers)
{
handler.Handle(instance);
}
}
}
При этом вы можете определить свои обработчики на более высоком уровне в вашей архитектуре и подключить ноль, один или несколько обработчиков для каждого бизнес -мероприятия. Вы можете ввести контекст в обработчик.
Мы предоставляем нашим клиентам возможность следовать подходу, запрашиваемому стартером темы. Чтобы сделать это, мы даже реализовали аналогичное решение (объектно -учебное заведение и другие события ObjectContext и ObjectStateManager) в нашем продукте ExpressApp Framework (XAF). Это работает без каких -либо проблем в большинстве сценариев, поскольку сущности имеют такое же время жизни, что и «контекст». Это также помогает нам улучшить удобство использования для наших клиентов, которые сталкиваются с одинаковыми трудностями при разработке своих моделей данных и бизнес -логики.
В нашем случае модель домена не сочетается с конкретной технологией постоянства, потому что у нас есть специальная абстракция «объектно -пространство» в контексте ORM (в дополнение к структуре сущности наш продукт поддерживает наши внутренние ORM - экспресс -постоянные объекты (xpo )).
Итак, мы предлагаем нашим клиентам интерфейс iobjectspacelink (с одним свойством iobjectspace), который должен быть реализован организациями, требующими контекста для их бизнес -логики.
Кроме того, мы предоставляем интерфейс ixafentityObject (с помощью вспомогаемых, загруженных методов воздействия) для самых популярных бизнес -правил. Вот пример того, как сущность реализует оба интерфейса из нашего BCL:
// IObjectSpaceLink
IObjectSpace IObjectSpaceLink.ObjectSpace {
get { return objectSpace; }
set { objectSpace = value; }
}
// IXafEntityObject
void IXafEntityObject.OnCreated() {
KpiInstance kpiInstance = (KpiInstance)objectSpace.CreateObject(typeof(KpiInstance));
kpiInstance.KpiDefinition = this;
KpiInstances.Add(kpiInstance);
Range = DevExpress.ExpressApp.Kpi.DateRangeRepository.FindRange("Now");
RangeToCompare = DevExpress.ExpressApp.Kpi.DateRangeRepository.FindRange("Now");
}
void IXafEntityObject.OnSaving() {}
void IXafEntityObject.OnLoaded() {}
В свою очередь, вот код нашей структуры, который связывает эти части внутренне (ниже предназначена для Entity Framework 6).
private void ObjectContext_SavingChanges(Object sender, EventArgs e) {
IList modifiedObjects = GetModifiedObjects();
foreach(Object obj in modifiedObjects) {
if(obj is IXafEntityObject) {
((IXafEntityObject)obj).OnSaving();
}
}
}
private void ObjectContext_ObjectMaterialized(Object sender, ObjectMaterializedEventArgs e) {
if(e.Entity is IXafEntityObject) {
((IXafEntityObject)e.Entity).OnLoaded();
}
}
private void ObjectStateManager_ObjectStateManagerChanged(Object sender, CollectionChangeEventArgs e) {
if(e.Action == CollectionChangeAction.Add) {
if(e.Element is INotifyPropertyChanged) {
((INotifyPropertyChanged)e.Element).PropertyChanged += new PropertyChangedEventHandler(Object_PropertyChanged);
}
if(e.Element is IObjectSpaceLink) {
((IObjectSpaceLink)e.Element).ObjectSpace = this;
}
}
else if(e.Action == CollectionChangeAction.Remove) {
if(e.Element is INotifyPropertyChanged) {
((INotifyPropertyChanged)e.Element).PropertyChanged -= new PropertyChangedEventHandler(Object_PropertyChanged);
}
if(e.Element is IObjectSpaceLink) {
((IObjectSpaceLink)e.Element).ObjectSpace = null;
}
}
OnObjectStateManagerChanged(e);
}
public virtual Object CreateObject(Type type) {
Guard.ArgumentNotNull(type, "type");
CheckIsDisposed();
Object obj = CreateObjectCore(type);
if(obj is IXafEntityObject) {
((IXafEntityObject)obj).OnCreated();
}
SetModified(obj);
return obj;
}
Я надеюсь, что эта информация поможет вам.