Резюме
В Entity Framework Core [Code-First] возможно ли отобразить навигационное свойство через частное (или даже публичное) вспомогательное поле этого навигационного свойства? По сути, вместо сопоставления это как:
modelBuilder.Entity<MyEntity>().HasMany(e => e.NavProperty)...
Можем ли мы отобразить это как (по сути, игнорируя Reflection или жестко закодированные строки для краткости):
modelBuilder.Entity<MyEntity>().HasMany(e => e.NavProperty._Data)...
Если NavProperty
рассматривается как навигационное свойство и обрабатывать отношения (т. Е. Внешний ключ)?
Кажется, я не могу понять конфигурацию отображения Fluent API, необходимую для достижения такого рода результата. Кажется, я вспомнил, как делал это раньше в EF 6, но, к сожалению, у меня больше нет исходного кода для этого проекта.
Detail
Более полный пример (C #, .NET Standard 2.2., Entity Framework Core 2.2 [Code-First]):
public class Customer
{
public int CustomerID { get; set; }
public string Name { get; set; }
// ...
public OrderCollection Orders { get; set; }
public Customer()
{
}
}
public class Order
{
public int OrderID { get; set; }
public string OrderNo { get; set; }
public bool Shipped { get; set; }
// ...
public Customer Customer { get; set; }
public Order()
{
}
}
public class OrderCollection : IReadOnlyCollection<Order>
{
private HashSet<Order> orders = new HashSet<Order>();
public OrderCollection()
{
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.orders.GetEnumerator();
}
public void Add(Order order)
{
this.orders.Add(order);
// ... Other logic here
}
public bool Contains(Order order)
{
// ... Other logic here
return this.orders.Contains(order);
}
}
// The DbContext Class...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//... Other models setup / plumbing completed
// How do we map the sub property / field??
modelBuilder.Entity<Customer>().HasMany(customer => customer.Orders).WithOne(order => order.Customer);
}
Пример несколько надуманный, но довольно простой, однако, только для быстрого ознакомления:
По сути, OrderCollection
- это оболочка для частного поля orders
HashSet, благодаря которому мы можем инкапсулировать реальные данные из мутаций и вместо этого демонстрировать поведение, которое нам нужно, через интерфейс (-ы), который нам нужен. Это также позволяет обрабатывать события домена и / или другие проблемы в наиболее подходящее время, когда вызывающий абонент / владелец не знает деталей или не должен дублировать логику во всей модели домена (т. Е. Выставление счетов также будет иметь коллекцию заказов, как и качество Контроль и т. Д.). Это также предотвращает утечку зависимостей и сквозных проблем в модель основного домена.
Мозговой
Вот некоторые идеи, которые у меня были для решения проблемы:
1) Имейте OrderCollection
наследование от чего-то вроде HashSet<T>
, ReadOnlyCollection<T>
и т. Д. И просто переопределяйте методы, которые я не хочу раскрывать. В лучшем случае это кажется хакерским и хрупким (т. Е. Мы нарушаем практику «композиция благосклонности над наследством» из-за жуткой магии вуду).
2) Просто отбросьте идею «Коллекции» и поместите вспомогательное поле и всю логику для элемента в объектную модель, что является нарушением DRY (другие модели будут использовать API такого же типа для свойства Orders
) и SRP, потому что теперь мой Customer
объект знает, как (то есть детали реализации того, как) обрабатывать добавление Order
к себе. Это плохой дизайн.
3) Обрабатывать навигационное свойство вручную через пользовательские SQL / репозитории / геттеры и сеттеры / и т. Д.? Похоже, EF должен делать все это под капотом, и это будет «изобретать велосипед».
Я пытался использовать ValueConverters
, но, похоже, они предназначены для обработки нюансов / эзотерических проблем с типами базы данных и типами .NET CLR, которые маршалируются взад и вперед. Возможно, это - лучшее решение, но для корректной работы ему нужен конкретный тип конструкции ValueConverter?
Любая помощь или понимание приветствуется! Спасибо!