Я создаю веб-сайт, и данные будут отправлены из внешнего приложения, которое имеет базу данных, полную данных, только часть которых необходима для веб-сайта. Под «частями» я подразумеваю некоторые строки в каждой таблице, но не все из них.
На данный момент это тот бизнес, который управляет благотворительными ваучерами, и у них есть клиенты, у которых есть счета у них. Благотворительные организации могут захотеть войти на веб-сайт и просмотреть информацию о деньгах, выплаченных им, а клиенты могут захотеть войти в систему и увидеть информацию о своей учетной записи.
Однако количество клиентов, которые захотят войти в систему онлайн, будет составлять лишь небольшой процент от тех, у кого есть аккаунты. Мы хотим избежать загрузки всей информации о клиентах и благотворительных организациях, так как это будет огромный объем данных, которые необходимо обновлять и которые в большинстве случаев не будут использоваться.
Проблема возникает, когда у нас есть выданный ваучер, но у клиента недостаточно денег на счету для его оплаты. В таком случае ваучер удерживается в ожидании депозита клиента. Благотворительные организации хотят видеть список имеющихся ваучеров, но им не показывают имена клиентов, они видят только детали ваучера, такие как дата, сумма и номер.
В идеале я хотел бы, чтобы база данных веб-сайта была полностью реляционной, но это вызовет проблему с отсутствующими данными. Например, если мы загрузим данные удерживаемого ваучера, где данные клиента отсутствуют в базе данных веб-сайта (поскольку они не имеют доступа через веб-сайт), то вставка в таблицу HeldVouchers завершится ошибкой, поскольку ссылка внешнего ключа в таблицу Customers будет указывать на клиента, которого нет в базе данных.
Я мог бы сделать все внешние ссылки обнуляемыми, но это все равно не поможет, потому что идентификатор клиента не будет нулевым, он будет содержать идентификатор клиента в основной базе данных.
Я мог проверить при загрузке, и если удерживаемый ваучер был загружен для клиента, которого нет в базе данных, я мог установить значение CustomerID равным нулю. Это было бы хорошо, за исключением того, что если этот клиент затем захочет получить доступ к веб-сайту, и мы загрузим его данные, нам тогда придется обновить таблицу HeldVouchers. Это вызовет много дополнительной работы и много дополнительных загрузок.
Кто-нибудь знает, как с этим справиться? Моя единственная мысль до сих пор заключалась в том, чтобы сделать веб-базу данных полностью нереляционной (что мне очень не нравится делать), а затем добавить методы расширения к сущностям, которые имитировали бы сгенерированные EF, за исключением того, что они перешли бы непосредственно к соответствующий DbSet и извлекать любые объекты, которые соответствуют ссылке на «внешний ключ».
Я попробовал это и придумал общий метод расширения, который работает, но имеет как минимум два очень серьезных недостатка...
public static List<T> NavColl<T>(this EntityInterface entity, Func<T, bool> f)
where T : class, EntityInterface {
return Ctx.Set<T>().ToList().Where(f).ToList();
}
(Этот метод возвращает эквивалент свойства навигации, которое является коллекцией. У меня есть аналогичный, который ищет один объект).
Если у вас есть благотворительный объект (хитро названный «благотворительность») и вы хотите получить удерживаемые ваучеры, вы можете сделать что-то вроде этого...
charity.NavColl<HeldVoucher>(ca => ca.CharityID == charity.ID)
Первый недостаток заключается в том, что единственный способ, который я мог видеть, чтобы позволить передачу Func в метод расширения и не заставить Linq-To-Entities вызывать шипящую подгонку, состоял в том, чтобы перечислить DbSet до применения Func. Если там много данных, это может значительно замедлить запрос.
Возможно, более серьезным (поскольку я не ожидаю, что производительность будет серьезной проблемой) является тот факт, что метод расширения нуждается в контексте для работы. На данный момент у меня есть объекты в отдельном проекте от модели EF, так как это позволяет мне ссылаться на объекты из любого проекта в решении, при этом этим проектам не требуется ссылка на проект модели. Это помогает разделить слои и позволяет проводить тестирование и т. д.
Однако, если методу расширения требуется контекст, проекту сущностей нужна ссылка на проект модели, что вызывает циклическую ссылку (поскольку модель должна знать о сущностях). Я не могу поместить метод расширения в модельный проект, так как тогда мне пришлось бы ссылаться на него из каждого проекта, который хотел использовать сущности, что противоречит всей цели выделения сущностей в их собственный проект.
У кого-нибудь есть идеи? Извините, это был немного длинный вопрос, но я хотел убедиться, что я ясно объяснил проблему.