Дело в том, что когда владельцу назначен элемент, любой другой владелец теряет право собственности на этот элемент (и его ссылка на элемент устанавливается на ноль).
Самый простой способ добиться этого - инвертировать отношения (т. Е. Кто хранит ссылку на другого)
public Item
{
public Owner Owner { get; set; }
}
Вы также можете использовать Owner.Id
или аналогичный действительный идентификатор, но ответ остается прежним.
Таким образом, каждый элемент имеет только одну «коробку» для регистрации владельца. Любая регистрация, которая происходит эффективно, перезаписывает ранее существовавшего владельца, что вам и нужно.
Конечно, поскольку вы хотите, чтобы отношения были в основном симметричными, вы можете достичь того же, имея ссылку в классе Owner
. То, как вы это делаете, не имеет большого значения, используйте тот, который имеет для вас наибольшее значение (вы назначаете элементы владельцам или назначаете владельцев на элементы? Это семантическая разница, а не техническая)
Мне нужно реализовать отношения между двумя объектами Владелец и Предмет так, чтобы владелец владел 0..1 предметами, и каждый элемент мог принадлежать только одному владельцу за один раз.
Это уже не так просто исправить, потому что вы не можете автоматизировать это поведение, если хотите, чтобы эта логика применялась к обеим сторонам отношения.
Чтобы поддержать уникальность (хотя и обнуляемую или нет) на обоих концах отношений, вам придется использовать явную бизнес-логику, чтобы подтвердить, что уникальность поддерживается.
В этом нет ничего хитрого. Это становится вопросом принудительной проверки, когда кто-то хочет добавить новое отношение Владелец-Предмет. Одним из таких примеров может быть:
public class Item
{
public Owner Owner { get; private set }
public void SetOwner(Owner owner)
{
if(!owner.OwnsItem)
{
this.Owner = owner;
}
else
{
//Do nothing, throw an exception, log a message, ...
}
}
}
public class Owner
{
public bool OwnsItem()
{
return ListOfAllItems.Any(item => item.Owner == this);
}
}
Примечания
- Я пропустил, как вы делаете проверку на равенство для владельцев. Скорее всего, вы бы проверили значение идентификатора, но ваш вопрос не прояснил это. Используйте любую проверку на равенство.
- Я также пропустил нулевую проверку параметра
owner
. Неясно, откажется ли когда-либо предмет от или нет. Добавьте его, если оно имеет отношение к вашему делу.
- Это требует, чтобы у вас был доступ к списку всех предметов, чтобы вы могли искать владельца. То, как вы получите этот список, во многом зависит от того, как вы храните свои данные, которые вы не упоминаете в своем вопросе. Для примера я предполагаю, что
ListOfAllItems
дает вам именно то, что говорится.
- Логика
OwnsItem()
не имеет в классе Owner
, если вы этого не хотите. Это имеет смысл с точки зрения DDD, но вы также можете поместить его в отдельный объект проверки или хранилище. Все зависит от вашей архитектуры, и ваш вопрос недостаточно раскрыт, чтобы я мог на него ответить окончательно.
- Если вы хотите быть умным и давать обоим классам ссылку друг на друга, следите за бесконечной рекурсией, когда каждый элемент пытается обновить свойство своего ссылочного элемента. Это можно сделать, но я советую по возможности избегать его по двум причинам:
- Сокращает необходимость обработки данных.
- Это предотвращает возможность того, что ваши данные могут быть противоречивыми или противоречащими друг другу (например, владелец, который ссылается на элемент, который ссылается на другого владельца)