Привет всем!
Вопрос у меня прежде всего к gandjustas, IB и пр. сторонникам анемичной модели с навигационным доступом (под этими терминами понимаю
этоАвтор: IB
Дата: 29.05.09
). Хотя, буду рад услышать доводы всех, кто захочет ответить.
Когда речь идет о стыке бизнес логики (BLL) с хранилищем данных (включая все промежуточные слои типа Репозитория, DAL и т.п.), то тут я скорее на стороне упомянутых выше участников форума.
Но когда речь идет о стыке представления (PL) и бизнес логики (BLL), то тут меня охватывают сомнения: модель работы с данными более естественна для GUI и при этом совместима с Transaction Script?
Как правильнее организовать представление составных сущностей на клиенте, сервере и передачу их с BLL на PL?
Уточню реализацию: клиент — WinForms в перспективой перехода на WPF, сервер — WinService на C#, транспорт — WCF.
Поясню на модельном примере.
Допустим есть сущности "Накладная" и "Поставщик". Накладная имеет ссылку на Поставщика.
-- работаю с MS SQL, поэтому скрипт смахивает на Transact SQL
CREATE TABLE [Поставщик]
(
[ПоставщикID] INT NOT NULL,
[Наименование] VARCHAR(100) DEFAULT '',
[ИНН] VARCHAR(15) DEFAULT '',
...
CONSTRAINT [PK_ПоставщикID] PRAIMARY KEY ([ПоставщикID]),
)
CREATE TABLE [Накладная]
(
[НакладнаяID] INT NOT NULL,
[Номер] VARCHAR(10) DEFAULT '',
[Дата] DATETIME NOT NULL,
[ПоставщикID] INT NOT NULL,
...
CONSTRAINT [PK_НакладнаяID] PRAIMARY KEY ([НакладнаяID])
CONSTRAINT [FK_Накладная_Поставщик] FOREIGN KEY ([ПоставщикID])
REFERENCES [Поставщик] ([ПоставщикID])
)
На клиенте (WinForms с его "коробочным" DataBinding'ом) для редактирования сущности "Накладная" нужно иметь возможность не только отредактировать номер, дату и т.п. "скалярные" поля накладной, но и выбрать в отдельном диалоге поставщика. При этом, допустим, на форме о поставщике мы должны видеть его ИНН и наименование.
Для естественной работы в WinForm'овским DataBinding'ом накладную надо представить как один класс со свойствами, отображающими все характеристики как самой накладной, так поставщика, на которого она ссылается.
По-моему, что класс накладной, экземпляр которого будет привязана к контролам формы, должна являться оберткой для класса WCF-ного DataContract'а, и поддерживать нижеприведенный интерфейс:
interface IНакладная_Editable : INotifyPropertyChanged, IEditableObject
{
// скалярные свойства накладной
int НакладнаяID { get; }
string Номер { get; set; }
DateTime Дата { get; set; }
...
// свойства поставщика
IПоставщик Поставщик { get; set; }
int ПоставщикID { get; }
string ИНН_Поставщика { get; }
string Наименование_Поставщика { get; }
// всевозможные INotifyPropertyChanged, IEditableObject
....
}
И тут вопрос: как реализовать класс самого DataContract'а (тот самый, который будет завернут в класс с интерфейсом IНакладная_Editable)?
Так:
class Накладная
{
public int НакладнаяID { get; private set; }
public string Номер { get; set; }
public DateTime Дата { get; set; }
public int ПоставщикID { get; private set; }
public string INN { get; set; }
public string Name { get; set; }
}
Или так:
class Поставщик
{
public int ПоставщикID { get; private set; }
public string INN { get; set; }
public string Name { get; set; }
}
class Накладная
{
public int НакладнаяID { get; private set; }
public string Номер { get; set; }
public DateTime Дата { get; set; }
Поставщик Поставщик { get; set; }
}
В первом случае не надо никаких преобразований структуры данных при передаче из BLL на PL и обратно (считаем, что на BLL реализован Transaction Script), но как тогда быть при смене поставщика в форме? Надо ведь сменить значения во всех свойствах, относящихся к поставщику...
Во втором случае смена поставщика пользователем в PL реализуется легко и красиво, но нужен некий Mapper между представлением данных на сервере приложения и на клиенте. Т.е. преобразователь [Transaction Script] в [Anemic Domain Model] и обратно. Что, по-моему, тоже извращение какое-то...
Красота — наивысшая степень целесообразности. (c) И. Ефремов