Можно ли использовать Entity Framework при отсутствии реляционных данных?

Я создаю веб-сайт, и данные будут отправлены из внешнего приложения, которое имеет базу данных, полную данных, только часть которых необходима для веб-сайта. Под «частями» я подразумеваю некоторые строки в каждой таблице, но не все из них.

На данный момент это тот бизнес, который управляет благотворительными ваучерами, и у них есть клиенты, у которых есть счета у них. Благотворительные организации могут захотеть войти на веб-сайт и просмотреть информацию о деньгах, выплаченных им, а клиенты могут захотеть войти в систему и увидеть информацию о своей учетной записи.

Однако количество клиентов, которые захотят войти в систему онлайн, будет составлять лишь небольшой процент от тех, у кого есть аккаунты. Мы хотим избежать загрузки всей информации о клиентах и ​​благотворительных организациях, так как это будет огромный объем данных, которые необходимо обновлять и которые в большинстве случаев не будут использоваться.

Проблема возникает, когда у нас есть выданный ваучер, но у клиента недостаточно денег на счету для его оплаты. В таком случае ваучер удерживается в ожидании депозита клиента. Благотворительные организации хотят видеть список имеющихся ваучеров, но им не показывают имена клиентов, они видят только детали ваучера, такие как дата, сумма и номер.

В идеале я хотел бы, чтобы база данных веб-сайта была полностью реляционной, но это вызовет проблему с отсутствующими данными. Например, если мы загрузим данные удерживаемого ваучера, где данные клиента отсутствуют в базе данных веб-сайта (поскольку они не имеют доступа через веб-сайт), то вставка в таблицу 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, так как это позволяет мне ссылаться на объекты из любого проекта в решении, при этом этим проектам не требуется ссылка на проект модели. Это помогает разделить слои и позволяет проводить тестирование и т. д.

Однако, если методу расширения требуется контекст, проекту сущностей нужна ссылка на проект модели, что вызывает циклическую ссылку (поскольку модель должна знать о сущностях). Я не могу поместить метод расширения в модельный проект, так как тогда мне пришлось бы ссылаться на него из каждого проекта, который хотел использовать сущности, что противоречит всей цели выделения сущностей в их собственный проект.

У кого-нибудь есть идеи? Извините, это был немного длинный вопрос, но я хотел убедиться, что я ясно объяснил проблему.


person Avrohom Yisroel    schedule 12.03.2014    source источник


Ответы (1)


Первая проблема, с которой мы столкнулись, связана с терминологией. База данных, в которой отсутствуют внешние ключи, не является нереляционной. Это по-прежнему реляционная база данных, просто в ней нет DRI (декларативной ссылочной целостности).

Я думаю, вам придется проектировать базу данных без внешних ключей в тех случаях, когда данные могут отсутствовать. Это не помешает вам определить отношения между этими объектами в EF. Мы делаем это все время. Вы не указываете, используете ли вы EDMX или Code First. Мы используем EDMX, и в прошлом все наши объекты были сопоставлены с представлениями. Что касается EF, то в нашей базе данных не было отношений внешнего ключа (из-за сопоставления представлений), поэтому мы просто нарисовали их сами и получили полную поддержку свойств навигации между сущностями.

person Craig W.    schedule 12.03.2014
comment
Спасибо за разъяснение, вы правы, я имел в виду, что у меня нет DRI. Кстати, я использую edmx. Можете ли вы уточнить, как вы выполняете свойства навигации, когда знаете, что некоторые данные могут отсутствовать? Например, если вы добавите в файл edmx ссылку из удерживаемого ваучера на клиента, как EF обработает ее, если клиент не существует? Вот где я застрял. - person Avrohom Yisroel; 13.03.2014
comment
Вы просто не получите объект Customer, прикрепленный к HeldVoucher, свойство навигации будет нулевой ссылкой. Просто убедитесь, что вы установили отношение 0..1 в свойстве навигации клиента на HeldVoucher. - person Craig W.; 13.03.2014
comment
Извините за задержку с ответом. Мне потребовалось несколько прочтений вашего ответа, чтобы понять, что вы имели в виду. Я только что попробовал это, и это сработало именно так, как вы объяснили. Я удалил все отношения внешнего ключа из базы данных, обновил модель EF и все ассоциации, которые все еще были там, когда в базе данных отношения работали нормально. Еще раз спасибо. - person Avrohom Yisroel; 19.03.2014