Изменение атрибута
[ForeignKey("id")]
public virtual ICollection<SerStaHis> SerStaHis{ get; set; }
на
[ForeignKey("service_id")]
public virtual ICollection<SerStaHis> SerStaHis{ get; set; }
ForeignKey
работает по-разному при применении к свойству FK, свойству навигационной ссылки и свойству навигации по коллекции. При применении к свойству навигации по коллекции оно задает имя свойства FK связанного с объекта объекта.
Я лично нахожу ForeignKey
атрибут запутанным и подверженным ошибкам. Свободный API намного более интуитивен и обеспечивает намного лучший контроль. Свободная конфигурация для вашего сценария выглядит следующим образом:
modelBuilder.Entity<Ser>()
.HasMany(ser => ser.SerStaHis) // collection navigation property
.WithOne() // no reference navigation property
.HasForeignKey(serStaHis => serStaHis.service_id); // foreign key property
Необходимо не всегда вызывать отношения наследования в приложениях, которые совместно используют общую кодовую базу.В самом деле.
Существует старый прием UNIX, где Вы адаптируете поведение Вас приложение на основе argv [0], т.е., имя приложения. Если я вспоминаю правильно (и это были 20 лет, с тех пор как я посмотрел на него), rsh, и rlogin являются той же командой. Вы просто реализовываете конфигурацию во время выполнения на основе значения argv [0].
Если Вы хотите придерживаться конфигурации сборки, это - шаблон, который обычно используется. Ваша система сборки / make-файл определяет символ на команде как, APP_CONFIG, чтобы быть ненулевым значением затем, у Вас есть общее, включают файл с основными деталями конфигурации.
#define APP_A 1
#define APP_B 2
#ifndef APP_CONFIG
#error "APP_CONFIG needs to be set
#endif
#if APP_CONFIG == APP_A
#define APP_CONFIG_DEFINED
// other defines
#endif
#if APP_CONFIG == APP_B
#define APP_CONFIG_DEFINED
// other defines
#endif
#ifndef APP_CONFIG_DEFINED
#error "Undefined configuration"
#endif
Этот шаблон осуществляет это, конфигурация является определенной командной строкой и действительна.
То, что Вы пытаетесь сделать, кажется очень похожим на "Линейки продуктов". Университет Дыни Carnigie имеет превосходную страницу на шаблоне здесь: http://www.sei.cmu.edu/productlines/
Это - в основном способ создать различные версии одной части программного обеспечения с различными возможностями. Если Вы предполагаете, что чему-то нравится, Ускоряются Домой/Pro/Бизнес затем, Вы на правильном пути.
В то время как это не может быть точно, что Вы попытка, методы должны быть полезными.
Это звучит мне, что Вы могли бы посмотреть на модульное исполнение Вашего кода в отдельно скомпилированные элементы, создав варианты из выбора общих модулей и определенного для варианта (основного) модуля верхнего уровня.
Затем управляйте, которые из этих частей входят в сборку, которой заголовочные файлы используются в компиляции верхнего уровня и какие .obj файлы Вы включаете в фазу компоновщика.
Вы могли бы найти эту определенную борьбу сначала. В конечном счете у Вас должны быть более надежная и конструкция поддающаяся проверке и процесс техобслуживания. Необходимо также смочь сделать лучше тестирование, не волнуясь обо всех #if изменениях.
Я надеюсь, что Ваше приложение просто еще не ужасно крупно, и распутывание модуляризации его функций не должно будет иметь дело с большим комком грязи.
В какой-то момент Вам, возможно, понадобились бы проверки на этапе выполнения, чтобы проверить, что сборка использовала последовательные компоненты для конфигурации приложения, которую Вы предназначили, но это может быть вычислено позже. Можно также достигнуть некоторой проверки непротиворечивости времени компиляции, но Вы получите максимум от этого с заголовочными файлами и подписями точек входа в зависимые модули, которые входят в конкретную комбинацию.
Это - та же игра, используете ли Вы классы C++ или действуете в значительной степени на общеязыковом уровне C/C++.
При использовании C++ не был должен A, B, и приложения C наследовались от общего предка? Это было бы OO способ решить проблему.
Можно также найти некоторую справку в этой подобной, которую я спросил: Запись межплатформенных приложений в C
Проблема состоит в том, что с помощью #if директивы с именем это - неопределенные действия, как будто это определяется как 0. Этого можно было избежать, всегда делая #ifdef сначала, но это является и громоздким и подверженным ошибкам.
Немного лучший путь состоит в том, чтобы использовать искажение пространства имен и пространство имен.
Например.
namespace AppA {
// application A specific
}
namespace AppB {
// application B specific
}
И используйте Вас app_defines.h, чтобы сделать искажение пространства имен
#if compiler_option_for_appA
namespace Application = AppA;
#elif compiler_option_for_appB
namespace Application = AppB;
#endif
Или, если более сложные комбинации, вложение пространства имен
namespace Application
{
#if compiler_option_for_appA
using namespace AppA;
#elif compiler_option_for_appB
using namespace AppB;
#endif
}
Или любая комбинация вышеупомянутого.
Преимущество состоит в том, что, когда Вы забываете заголовок, Вы получите неизвестные ошибки пространства имен из своего компилятора i.s.o. тихого сбоя, потому что ПРИЛОЖЕНИЕ принято значение по умолчанию к 0.
Однако я был в аналогичной ситуации, я принял решение осуществить рефакторинг все во многие библиотеки, из которых подавляющее большинство было совместно использовано код, и позвольте системе управления версиями обработать то, что идет, где в другом приложении i.s.o. доверие определяет и т.д. в коде.
Это работает немного лучше в моем opionon, но я знаю, что это, оказывается, очень специализировано, YMMV.
Сделайте что-то вроде этого:
CommonApp +----- AppExtender + = containment
^ ^ ^
| | | ^ = ineritance
AppA AppB AppC |
Поместите свой общий код в класс CommonApp и поместите вызовы в интерфейс 'AppExtender' в стратегических местах. Например, интерфейс AppExtender будет иметь функции как afterStartup, afterConfigurationRead, beforeExit, getWindowTitle...
Затем в основном каждого приложения, создайте корректный расширитель и передайте его CommonApp:
--- main_a.cpp
CommonApp application;
AppA appA;
application.setExtender(&appA);
application.run();
--- main_a.cpp
CommonApp application;
AppB appB;
application.setExtender(&appB);
application.run();
Однако я выстрелил себе в ногу этим утром и пропал впустую далеко к большому количеству времени путем простого исключения строки к #include "app_defines.h" из одного файла. Все скомпилировало прекрасный, но приложение, разрушенное с AVS при запуске.
Существует простая фиксация к этой проблеме, включите предупреждения так, чтобы, если APP_B не определяется затем, Ваш проект не компилировал (или по крайней мере производит достаточно предупреждений так, чтобы Вы знали, что что-то неправильно).
Вы могли бы хотеть взглянуть на инструменты, которые поддерживают разработку линеек продуктов и способствуют явному различному управлению структурированным способом.
Один из этих инструментов чист:: варианты от чистых систем, который способен к управлению изменчивостью через модели функции и отслеживания различных мест функция, реализованы в исходном коде.
Можно выбрать определенное подмножество функции из модели функции, ограничения между функциями проверяются, и конкретный вариант линейки продуктов, то есть, определенного набора файлов исходного кода, и определяет, создается.
Для решения конкретной технической проблемы незнания, когда определение препроцессора определено или нет, существует простой, но эффективный прием.
Вместо -
#define APP_A 0
#define APP_B 1
#define APP_C 2
Использование -
#define APP_A() 0
#define APP_B() 1
#define APP_C() 2
И в том месте, где запрашиваются версии, -
#if APPLICATION >= APP_B()
// extra features for APPB and APP_C
#endif
(возможно, что-то сделать с APPLICATION в том же духе).
Попытка использовать неопределенную функцию препроцессора выдаст предупреждение или ошибка большинства компиляторов (тогда как неопределенный препроцессор определяет просто молча оценивает 0). Если заголовок не включен, вы сразу заметите это, особенно если вы «воспринимаете предупреждения как ошибки».
Посмотрите Современный дизайн C ++ Александреску . Он представляет разработку на основе политики с использованием шаблонов. По сути, этот подход является расширением шаблона стратегии, с той лишь разницей, что все выборы делаются во время компиляции. Я думаю, что подход Александреску похож на использование идиомы PIMPL, но реализуется с помощью шаблонов.
Вы должны использовать флаги предварительной обработки в общем заголовочном файле, чтобы выбрать, какую реализацию вы хотите скомпилировать, и ввести ее в type используется во всех экземплярах шаблона в других местах вашей кодовой базы.