Здравствуйте, syomin, Вы писали:
S>Добрый день!
S>Только начинаю осваивать Entity Framework, поэтому вопрос в общем-то дилетантский...
S>Построил я модель предметной области по существующей базе данных с использование мастера из состава Visual Studio. В базе данных есть две таблицы: Customers и Products, для каждой из них определен первичный ключ (поле Id типа Guid). В таблице Products также имеется поле CustomerId и соответствующий внешний ключ, который связывает обе таблицы.
S>Для примера рассмотрим класс Product, который сгенерировал нам мастер: S>
S>public partial class Product : EntityObject
S>{
S> public Guid Id
S> {
S> get { ... }
S> set { ... }
S> }
S> public Guid CustomerId
S> {
S> get { ... }
S> set { ... }
S> }
S> public Customer Customer
S> {
S> get { ... }
S> set { ... }
S> }
S>}
S>
S>На мой взгляд, свойства Id и CustomerId избыточны и им не место в этом классе, поскольку они имеют отношение только к тому, каким образом данный объект хранится в базе данных. От них как-нибудь можно избавиться?
1)Написать свой ORM
2)Сделать свойства private
3)Включить мозг и понять что убрав эти свойства ты не сможешь написать Linq запрос, который вытянет Product по Id или все Product для одного Customer.
Потом сжечь все книги по ООП и выкинуть фаулера АКПП.
Здравствуйте, syomin, Вы писали:
S>Здравствуйте, HowardLovekraft, Вы писали:
HL>>Здравствуйте, syomin, Вы писали:
S>>>Первичный ключ используется базой данных для однозначной идентификации строки в таблице. S>Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы S>данных, то перечисленных выше полей быть не должно — достаточно просто ссылок. HL>>В предметной области объекты идентифицировать не нужно?
S>Отдельным идентификатором? Нет, достаточно просто ссылки на объект.
Хм. Предметная область это "складской учет", "управление производством", "контроль доступа". Идентифицируйте человека ссылкой на объект и расскажите, как это у вас получилось.
Здравствуйте, drol, Вы писали:
D>Здравствуйте, syomin, Вы писали:
S>>Зависит от условий задачи: дата рождения, место жительства, серия + номер паспорта и т.д. и т.п.
D>Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов.
Надо различать две задачи: идентификацию самих объектов предметной области, и идентификацию экземпляров классов в ООП. Идентификация объектов предметной области — широкая и местами сложная тема, в которой надо плясать в основном от требований к приложению. Идентификация экземпляров — вещь очень простая: у каждого объекта в памяти есть адрес, в дотнете можно сравнивать объекты на ссылочное равенство (ReferenceEquals). Суррогатные ключи в базе данных — это аналог адреса объекта для базы — нужен для удобного обращения к определенной строке таблицы. Строго говоря, primary key необходим ОРМ-у внутри себя для обеспечения identity mapping, а также для сохранения/удаления объектов в/из базы. То свойство/поле с первичным ключом, которое содержится в объекте — это не более чем копия настоящего значения primary key, и для ОРМ его наличие не играет особой роли. Если бы это было не так, ОРМ не смог бы обеспечить правильность работы при изменении пользователем первичного ключа в объекте. То есть наличие в объекте свойства Customer.CustomerID — это опция для удобства и для обеспечения возможности обращаться к primary key объекта из LINQ2Entity.
S>>Поймите простую вещь: если у нас первичный ключ является суррогатным, то в большинстве случаев никакого смысла показывать его пользователю нет,
D>Ничего подобного. Пользователь может его в виде компоненты http-ссылки наблюдать, например. А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим...
Ну это правильно, но вынужденно, т.к. для URL необходим текстовый аналог уникальной ссылки на объект, и использовать для этого данные предметной области неудобно.
Здравствуйте, syomin, Вы писали:
S>>>поскольку составной первичный ключ нельзя использовать для описания внешних ключей. G>>С чего ты это взял? Все можно. S>Ссылку можно?
Здравствуйте, syomin, Вы писали:
D>>>>Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов. S>>>В элементарном сферовакуумном примере для обеспечения идентичности объекта может использоваться связка из гражданства и номера паспорта человека. При этом сделать такой первичный ключ для соответствующей таблицы в БД конечно можно, но неудобно, поскольку составной первичный ключ нельзя использовать для описания внешних ключей. G>>С чего ты это взял? Все можно. S>Ссылку можно? http://msdn.microsoft.com/en-us/library/ms174979.aspx
< table_constraint > ::=
[ CONSTRAINT constraint_name ]
{
{ PRIMARY KEY | UNIQUE }
[ CLUSTERED | NONCLUSTERED ]
(column [ ASC | DESC ] [ ,...n ] )
[
WITH FILLFACTOR = fillfactor
|WITH ( <index_option> [ , ...n ] )
]
[ ON { partition_scheme_name (partition_column_name)
| filegroup | "default" } ]
| FOREIGN KEY
( column [ ,...n ] )
REFERENCES referenced_table_name [ ( ref_column [ ,...n ] ) ]
[ ON DELETE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
[ ON UPDATE { NO ACTION | CASCADE | SET NULL | SET DEFAULT } ]
[ NOT FOR REPLICATION ]
| CHECK [ NOT FOR REPLICATION ] ( logical_expression )
}
Выделенное то что тебе нужно.
D>>>>А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим... S>>>В описанном случае не нужен. Приложение уже есть и работает, теперь хочется добавить к нему базу данных, чтобы обеспечить персистентность. G>>Как только объекты начинают "жить" дольше приложения сразу же стандартные средства ООП перестают работать. S>Ну так и пусть ключи будут в storage model — я же не против. Другое дело, что не очень хочется их в conceptual model тащить...
Еще раз, не все сценарии бизнес-логики и даже UI возможны только на ссылках, потому что их время жизни гораздо меньше времени жизни "объектов".
То что ты написал программу так, что таких сценариев, нет никого не интересует, завтра у тебя появится такой сценарий и придется тащить везде ключи.
Поэтому производители ORM, несмотря на "чувство прекрасного", которое противоречит здравому смыслу, всетаки включают в модель ключи.
Кстати, как ты предполагаешь делать выборку по ключу, если у тебя их нет?
Здравствуйте, HowardLovekraft, Вы писали:
HL>Здравствуйте, syomin, Вы писали:
S>>Первичный ключ используется базой данных для однозначной идентификации строки в таблице. S>Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы S>данных, то перечисленных выше полей быть не должно — достаточно просто ссылок. HL>В предметной области объекты идентифицировать не нужно?
Отдельным идентификатором? Нет, достаточно просто ссылки на объект.
Здравствуйте, syomin, Вы писали:
G>>1)Написать свой ORM S>Хотелось бы использовать готовый.
Ксттаи в EF есть возможность свой генератор кода подсунуть — пользуйся. Только потом покажи нам что получилось.
G>>2)Сделать свойства private S>Некошерно. Я же знаю, что они там есть и это претит моему чувству прекрасного.
"Чувство прекрасного" в нашем деле зачастую противоречит здравому смыслы. Кроме того оно неформализуемо. Ты можешь до посинения доказывать что отсутствие ключей в классе сущности это "прекрасно", но если на форме, где отображается Product надо сделать ссылку на форму Customer, то все равно понадобится внешний ключ в Product или первичный в Customer. Причем в первой версии EF из "чувства прекрасного" не создавались поля внешних ключей, но почему-то включили их в четвертую версию.
G>>3)Включить мозг и понять что убрав эти свойства ты не сможешь написать Linq запрос, который вытянет Product по Id или все Product для одного Customer. S>Вы слишком узко смотрите на вещи. Первичный ключ используется базой данных для однозначной идентификации строки в таблице. Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы данных, то перечисленных выше полей быть не должно — достаточно просто ссылок. Думаю, технически это возможно.
Плохо думаешь. У обычных ссылок (указателей) слишком короткий срок жизни, чтобы покрыть все сценарии.
S>Другое дело, возможно ли это в EF.
Как раз в EF это возможно, по сравнению с многими другими мапперами, потому что можно свой шаблон генерации кода задавать.
Только не уверен, что получится маппить без ключей.
G>>Потом сжечь все книги по ООП и выкинуть фаулера АКПП. S>Не конструктивно.
Зато очень полезно.
Чувство прекрасного надо долго тренировать прежде чем оно перестанет тебя подводить. А чтение литературы по ООП препятствует такой тренировке.
Здравствуйте, syomin, Вы писали:
G>>Кстати, как ты предполагаешь делать выборку по ключу, если у тебя их нет?
S>Чтобы сделать выборку по ключу, нужно этот ключ откуда-то взять. Варианты: S>
S> ключ берется из конфигурационного файла, приходит по сети, его вводит пользователь т.д. и т.п. Я выше неоднократно писал, что такого в рассматриваемой системе нет. S> ключ берется из другой сущности, которая уже есть в БД. Здесь всё решается navigation properties, которые генерирует EF. S>
S>Другими словами, мне не нужно делать поиск по ключу в явном виде. Вообще. В неявном виде (т.е. в SQL запросе) ключ фигурирует, но эту работу ТЕОРЕТИЧЕСКИ мог бы взять на себя EF.
Тогда тебе не нужна БД и ORM — сериализуй граф в файл и восстанавливай оттуда при запуске приложения. Иначе у тебя lazy load быстренько сам вытянет всю базу, а это все равно дольше выйдет.
Только начинаю осваивать Entity Framework, поэтому вопрос в общем-то дилетантский...
Построил я модель предметной области по существующей базе данных с использование мастера из состава Visual Studio. В базе данных есть две таблицы: Customers и Products, для каждой из них определен первичный ключ (поле Id типа Guid). В таблице Products также имеется поле CustomerId и соответствующий внешний ключ, который связывает обе таблицы.
Для примера рассмотрим класс Product, который сгенерировал нам мастер:
public partial class Product : EntityObject
{
public Guid Id
{
get { ... }
set { ... }
}
public Guid CustomerId
{
get { ... }
set { ... }
}
public Customer Customer
{
get { ... }
set { ... }
}
}
На мой взгляд, свойства Id и CustomerId избыточны и им не место в этом классе, поскольку они имеют отношение только к тому, каким образом данный объект хранится в базе данных. От них как-нибудь можно избавиться?
G>1)Написать свой ORM
Хотелось бы использовать готовый.
G>2)Сделать свойства private
Некошерно. Я же знаю, что они там есть и это претит моему чувству прекрасного.
G>3)Включить мозг и понять что убрав эти свойства ты не сможешь написать Linq запрос, который вытянет Product по Id или все Product для одного Customer.
Вы слишком узко смотрите на вещи. Первичный ключ используется базой данных для однозначной идентификации строки в таблице. Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы данных, то перечисленных выше полей быть не должно — достаточно просто ссылок. Думаю, технически это возможно. Другое дело, возможно ли это в EF.
G>Потом сжечь все книги по ООП и выкинуть фаулера АКПП.
Не конструктивно.
Здравствуйте, syomin, Вы писали:
S>Первичный ключ используется базой данных для однозначной идентификации строки в таблице. S>Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы S>данных, то перечисленных выше полей быть не должно — достаточно просто ссылок.
В предметной области объекты идентифицировать не нужно?
S>>Отдельным идентификатором? Нет, достаточно просто ссылки на объект. HL>Хм. Предметная область это "складской учет", "управление производством", "контроль доступа". Идентифицируйте человека ссылкой на объект и расскажите, как это у вас получилось.
У меня не "складской учет", "управление производством", "контроль доступа". Опять же, если бы мне нужно было держать в базе данных перечень сотрудников, то сделал бы я табличку типа такой:
1. Первичный ключ (guid, генерируется базой данных автоматически при вставке новой записи).
2. Фамилия.
3. Имя.
4. Отчество.
Мне не нужно, чтобы первичный ключ "уходил" из системы дальше слоя работы с БД (например, в какие-то сторонние системы). Ведь что нужно пользователю:
1. Список всех сотрудников.
2. Список сотрудников, удовлетворяющих определенному критерию (например, с указанной фамилией).
Здравствуйте, syomin, Вы писали:
S>Мне не нужно, чтобы первичный ключ "уходил" из системы дальше слоя работы с БД (например, в какие-то сторонние системы). Ведь что нужно пользователю: S> S>1. Список всех сотрудников. S>2. Список сотрудников, удовлетворяющих определенному критерию (например, с указанной фамилией).
Ну и как Ваш пользователь будете различать сотрудников у которых полностью одинаковые ФИО ?
Здравствуйте, syomin, Вы писали:
S>Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы данных,
Задача ORM'ов — предоставление статически типизированного и, соответственно, проверяемого в compile time доступа к реляционным данным. Именно этого хотели авторы/пользователи ORM'ов с самого начала, но долго не могли сформулировать
S>Думаю, технически это возможно. Другое дело, возможно ли это в EF.
Технически возможно всё. Вопрос тольков том, готовы ли Вы уплатить цену этого технического решения ???
Здравствуйте, syomin, Вы писали:
S>>>Отдельным идентификатором? Нет, достаточно просто ссылки на объект. HL>>Хм. Предметная область это "складской учет", "управление производством", "контроль доступа". Идентифицируйте человека ссылкой на объект и расскажите, как это у вас получилось.
S>У меня не "складской учет", "управление производством", "контроль доступа".
Не суть важно. Это всего лишь примеры.
S>Опять же, если бы мне нужно было держать в базе данных перечень сотрудников, то сделал бы я S>табличку типа такой:
Фиг с ними, с табличками. Нет табличек. Есть люди. Рано или поздно возникнет задача — отличить одного человека от другого. Как?
D>Ну и как Ваш пользователь будете различать сотрудников у которых полностью одинаковые ФИО ?
Зависит от условий задачи: дата рождения, место жительства, серия + номер паспорта и т.д. и т.п. Поймите простую вещь: если у нас первичный ключ является суррогатным, то в большинстве случаев никакого смысла показывать его пользователю нет, поэтому и тащить его в приложении дальше слоя доступа к базе данных не нужно.
G>>>1)Написать свой ORM S>>Хотелось бы использовать готовый. G>Ксттаи в EF есть возможность свой генератор кода подсунуть — пользуйся. Только потом покажи нам что получилось.
Про генератор я в курсе, только тут это не поможет. Проблема не в том, чтобы избавиться от идентификаторов, а в том, чтобы переложить заботу о них на EF, оставив себе только ссылки. А тут нужна определенная логика в EF.
G>>>2)Сделать свойства private S>>Некошерно. Я же знаю, что они там есть и это претит моему чувству прекрасного. G>"Чувство прекрасного" в нашем деле зачастую противоречит здравому смыслы. Кроме того оно неформализуемо. Ты можешь до посинения доказывать что отсутствие ключей в классе сущности это "прекрасно", но если на форме, где отображается Product надо сделать ссылку на форму Customer, то все равно понадобится внешний ключ в Product или первичный в Customer.
В этом случае нам по-прежнему не нужен CustomerId в классе Product, поскольку EF генерирует нам свойство Customer, которое является ссылкой на соответствующего customer'а.
G>>>3)Включить мозг и понять что убрав эти свойства ты не сможешь написать Linq запрос, который вытянет Product по Id или все Product для одного Customer. G>Плохо думаешь. У обычных ссылок (указателей) слишком короткий срок жизни, чтобы покрыть все сценарии.
Мои сценарии покрывает. Вопрос ведь в том как сделать, а не почему нужны идентификаторы.
D>Задача ORM'ов — предоставление статически типизированного и, соответственно, проверяемого в compile time доступа к реляционным данным. Именно этого хотели авторы/пользователи ORM'ов с самого начала, но долго не могли сформулировать
Эту задачу успешно решает LINQ-To-SQL. У создателей EF были, по их словам, другие цели.
Здравствуйте, syomin, Вы писали:
G>>>>1)Написать свой ORM S>>>Хотелось бы использовать готовый. G>>Ксттаи в EF есть возможность свой генератор кода подсунуть — пользуйся. Только потом покажи нам что получилось.
S>Про генератор я в курсе, только тут это не поможет. Проблема не в том, чтобы избавиться от идентификаторов, а в том, чтобы переложить заботу о них на EF, оставив себе только ссылки. А тут нужна определенная логика в EF.
EF ориентируется на CSDL, там ключи есть, от этого никуда не денешься. Потому что иначе на eSQL выборку по ключу не напишешь вообще.
Маппинг на объекты — то что отлично контролируется в 4-ой версии.
G>>>>2)Сделать свойства private S>>>Некошерно. Я же знаю, что они там есть и это претит моему чувству прекрасного. G>>"Чувство прекрасного" в нашем деле зачастую противоречит здравому смыслы. Кроме того оно неформализуемо. Ты можешь до посинения доказывать что отсутствие ключей в классе сущности это "прекрасно", но если на форме, где отображается Product надо сделать ссылку на форму Customer, то все равно понадобится внешний ключ в Product или первичный в Customer.
S>В этом случае нам по-прежнему не нужен CustomerId в классе Product, поскольку EF генерирует нам свойство Customer, которое является ссылкой на соответствующего customer'а.
И что? Нужна ссылка в виде http://site/action/{а вот тут надо как-то указать кастомера}, если нету ключей в сущностях, то как указывать?
G>>>>3)Включить мозг и понять что убрав эти свойства ты не сможешь написать Linq запрос, который вытянет Product по Id или все Product для одного Customer. G>>Плохо думаешь. У обычных ссылок (указателей) слишком короткий срок жизни, чтобы покрыть все сценарии. S>Мои сценарии покрывает. Вопрос ведь в том как сделать, а не почему нужны идентификаторы.
А твои сценарии никого не интересуют. Если нужно чтобы твои покрывало — пиши ORM сам.
Здравствуйте, syomin, Вы писали:
D>>Ну и как Ваш пользователь будете различать сотрудников у которых полностью одинаковые ФИО ?
S>Зависит от условий задачи: дата рождения, место жительства, серия + номер паспорта и т.д. и т.п. Поймите простую вещь: если у нас первичный ключ является суррогатным, то в большинстве случаев никакого смысла показывать его пользователю нет, поэтому и тащить его в приложении дальше слоя доступа к базе данных не нужно.
Те то что не показывается пользователю вообще должно отсутствовать в бизнес-логике?
Здравствуйте, syomin, Вы писали:
S>Зависит от условий задачи: дата рождения, место жительства, серия + номер паспорта и т.д. и т.п.
Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов.
S>Поймите простую вещь: если у нас первичный ключ является суррогатным, то в большинстве случаев никакого смысла показывать его пользователю нет,
Ничего подобного. Пользователь может его в виде компоненты http-ссылки наблюдать, например. А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим...
D>Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов.
В элементарном сферовакуумном примере для обеспечения идентичности объекта может использоваться связка из гражданства и номера паспорта человека. При этом сделать такой первичный ключ для соответствующей таблицы в БД конечно можно, но неудобно, поскольку составной первичный ключ нельзя использовать для описания внешних ключей. В этом случае делают так: накладывают ограничение уникальности на пару полей "гражданство" и "номер паспорта" и добавляют суррогатный первичный ключ — вещь абсолютно синтетическую, которая нужна только на уровне базы данных и слоя доступа к ней.
D>Ничего подобного. Пользователь может его в виде компоненты http-ссылки наблюдать, например.
Я писал, что идентификатор объекта не передается за пределы приложения.
D>А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим...
В описанном случае не нужен. Приложение уже есть и работает, теперь хочется добавить к нему базу данных, чтобы обеспечить персистентность.
Здравствуйте, syomin, Вы писали:
S>Эту задачу успешно решает LINQ-To-SQL.
Поехали по кругу: сие задача всех ORM'ов. То что длительное время люди не могли её внятно сформулировать, и в результате породили таких монстров как Hibernate и EF — это совсем другой вопрос.
S>У создателей EF были, по их словам, другие цели.
А причём тут цели-то ??? Разговор о задачах, а они именно те самые.
D>Поехали по кругу: сие задача всех ORM'ов. То что длительное время люди не могли её внятно сформулировать, и в результате породили таких монстров как Hibernate и EF — это совсем другой вопрос.
Здравствуйте, syomin, Вы писали:
D>>Поехали по кругу: сие задача всех ORM'ов. То что длительное время люди не могли её внятно сформулировать, и в результате породили таких монстров как Hibernate и EF — это совсем другой вопрос.
S>Обратите внимание, что вопрос касается именно EF.
Все известные мне ORMы мапят как минимум первичные ключи на объекты.
Здравствуйте, syomin, Вы писали:
D>>Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов. S>В элементарном сферовакуумном примере для обеспечения идентичности объекта может использоваться связка из гражданства и номера паспорта человека. При этом сделать такой первичный ключ для соответствующей таблицы в БД конечно можно, но неудобно, поскольку составной первичный ключ нельзя использовать для описания внешних ключей.
С чего ты это взял? Все можно.
S>В этом случае делают так: накладывают ограничение уникальности на пару полей "гражданство" и "номер паспорта" и добавляют суррогатный первичный ключ — вещь абсолютно синтетическую, которая нужна только на уровне базы данных и слоя доступа к ней.
Это только соображения удобства.
D>>А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим... S>В описанном случае не нужен. Приложение уже есть и работает, теперь хочется добавить к нему базу данных, чтобы обеспечить персистентность.
Как только объекты начинают "жить" дольше приложения сразу же стандартные средства ООП перестают работать.
D>>>Ну вот видите — указателей/ссылок, даже в элементарном сферовакуумном примере, недостаточно для эффективного обеспечения identity объектов. S>>В элементарном сферовакуумном примере для обеспечения идентичности объекта может использоваться связка из гражданства и номера паспорта человека. При этом сделать такой первичный ключ для соответствующей таблицы в БД конечно можно, но неудобно, поскольку составной первичный ключ нельзя использовать для описания внешних ключей. G>С чего ты это взял? Все можно.
Ссылку можно?
D>>>А уж собственно потрохам приложения PK так и вообще на каждом шагу необходим... S>>В описанном случае не нужен. Приложение уже есть и работает, теперь хочется добавить к нему базу данных, чтобы обеспечить персистентность. G>Как только объекты начинают "жить" дольше приложения сразу же стандартные средства ООП перестают работать.
Ну так и пусть ключи будут в storage model — я же не против. Другое дело, что не очень хочется их в conceptual model тащить...
Здравствуйте, syomin, Вы писали:
S>Приложение уже есть и работает, теперь хочется добавить к нему базу данных, чтобы обеспечить персистентность.
Если у Вас более-менее сложная ООП-style модель данных, при разработке которой не учитывались вопросы сохраняемости, то добавить к такой конструкции "классический" persistence в БД => переписать почти всё что связано с оной моделью.
Вы точно уверены, что Вам именно БД нужна ? Для многих случаев ведь достаточно простейшей "залповой" сериализации всего графа объектов модели данных.
G>Кстати, как ты предполагаешь делать выборку по ключу, если у тебя их нет?
Чтобы сделать выборку по ключу, нужно этот ключ откуда-то взять. Варианты:
ключ берется из конфигурационного файла, приходит по сети, его вводит пользователь т.д. и т.п. Я выше неоднократно писал, что такого в рассматриваемой системе нет.
ключ берется из другой сущности, которая уже есть в БД. Здесь всё решается navigation properties, которые генерирует EF.
Другими словами, мне не нужно делать поиск по ключу в явном виде. Вообще. В неявном виде (т.е. в SQL запросе) ключ фигурирует, но эту работу ТЕОРЕТИЧЕСКИ мог бы взять на себя EF.
sto>Надо различать две задачи: идентификацию самих объектов предметной области, и идентификацию экземпляров классов в ООП. Идентификация объектов предметной области — широкая и местами сложная тема, в которой надо плясать в основном от требований к приложению. Идентификация экземпляров — вещь очень простая: у каждого объекта в памяти есть адрес, в дотнете можно сравнивать объекты на ссылочное равенство (ReferenceEquals). Суррогатные ключи в базе данных — это аналог адреса объекта для базы — нужен для удобного обращения к определенной строке таблицы. Строго говоря, primary key необходим ОРМ-у внутри себя для обеспечения identity mapping, а также для сохранения/удаления объектов в/из базы. То свойство/поле с первичным ключом, которое содержится в объекте — это не более чем копия настоящего значения primary key, и для ОРМ его наличие не играет особой роли. Если бы это было не так, ОРМ не смог бы обеспечить правильность работы при изменении пользователем первичного ключа в объекте. То есть наличие в объекте свойства Customer.CustomerID — это опция для удобства и для обеспечения возможности обращаться к primary key объекта из LINQ2Entity.
Спасибо за конструктивный ответ. Не подскажете, как можно сделать следующее:
Убрать свойство CustomerId из класса Product.
Убрать свойство Id у Product и Customer.
G>Тогда тебе не нужна БД и ORM — сериализуй граф в файл и восстанавливай оттуда при запуске приложения. Иначе у тебя lazy load быстренько сам вытянет всю базу, а это все равно дольше выйдет.
Возможный вариант, но хотелось бы использовать единое "хранилище" объектов для нескольких экземпляров приложения. Клиент-сервер, другими словами.
Здравствуйте, syomin, Вы писали:
G>>Тогда тебе не нужна БД и ORM — сериализуй граф в файл и восстанавливай оттуда при запуске приложения. Иначе у тебя lazy load быстренько сам вытянет всю базу, а это все равно дольше выйдет.
S>Возможный вариант, но хотелось бы использовать единое "хранилище" объектов для нескольких экземпляров приложения. Клиент-сервер, другими словами.
Ну тогда тебе остается только свой ORM писать, покажи потом что получилось.
Здравствуйте, syomin, Вы писали:
G>>Ну тогда тебе остается только свой ORM писать, покажи потом что получилось. S>Проще победить чувство прекрасного...
Тебе все равно придется это делать, твой подход к работе с данными положит приложение даже на небольших объемах.
S> Убрать свойство CustomerId из класса Product. S> Убрать свойство Id у Product и Customer. S>
Если использовать NHibernate, то CustomerId исчезнет. От Id избавляться не следует. Хотя бы потому, что в списке пользователю показывается облегчённый объект, а по клику открывается карточка полного объекта. По ссылкам объекты разные, Id — одинаковые.
Здравствуйте, syomin, Вы писали:
S>Добрый день!
S>Только начинаю осваивать Entity Framework, поэтому вопрос в общем-то дилетантский...
S>Построил я модель предметной области по существующей базе данных с использование мастера из состава Visual Studio. В базе данных есть две таблицы: Customers и Products, для каждой из них определен первичный ключ (поле Id типа Guid). В таблице Products также имеется поле CustomerId и соответствующий внешний ключ, который связывает обе таблицы.
Я понимаю чего вы хотите добиться и для себя я выбрал BLToolkit вместо EF отчасти из аналогичных соображений.
В EF кое-что могло бы быть упрощено если бы EntityObject уже содержал некий общий Id который все равно нужен в каждом дочернем объекте.
Но для второго ID (CustomerId) проблема проистекает из реляционной модели данных вообще. Эта модель нуждается в ID, чтобы описать связи между объектами.
Иначе загрузка одного объекта потянет за собой всю базу данных, что совершенно ни к чему.
Здравствуйте, henson, Вы писали:
H>Здравствуйте, syomin, Вы писали:
S>>Добрый день!
S>>Только начинаю осваивать Entity Framework, поэтому вопрос в общем-то дилетантский...
S>>Построил я модель предметной области по существующей базе данных с использование мастера из состава Visual Studio. В базе данных есть две таблицы: Customers и Products, для каждой из них определен первичный ключ (поле Id типа Guid). В таблице Products также имеется поле CustomerId и соответствующий внешний ключ, который связывает обе таблицы.
H>Я понимаю чего вы хотите добиться и для себя я выбрал BLToolkit вместо EF отчасти из аналогичных соображений.
булкит — по большей части маппер, не умеет он identity map, поэтому ключики должны быть явными.
H>В EF кое-что могло бы быть упрощено если бы EntityObject уже содержал некий общий Id который все равно нужен в каждом дочернем объекте.
EntityKey?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, henson, Вы писали:
H>>Здравствуйте, syomin, Вы писали:
S>>>Добрый день!
S>>>Только начинаю осваивать Entity Framework, поэтому вопрос в общем-то дилетантский...
S>>>Построил я модель предметной области по существующей базе данных с использование мастера из состава Visual Studio. В базе данных есть две таблицы: Customers и Products, для каждой из них определен первичный ключ (поле Id типа Guid). В таблице Products также имеется поле CustomerId и соответствующий внешний ключ, который связывает обе таблицы.
H>>Я понимаю чего вы хотите добиться и для себя я выбрал BLToolkit вместо EF отчасти из аналогичных соображений. G> G>булкит — по большей части маппер, не умеет он identity map, поэтому ключики должны быть явными.
Соображение было такое, что если EF этого не делает, то лучше использовать BLToolkit, который все остальное намного легче и быстрей, даже если автоматического identity mapping там тоже нет
H>>В EF кое-что могло бы быть упрощено если бы EntityObject уже содержал некий общий Id который все равно нужен в каждом дочернем объекте. G>EntityKey?
EntityKey все-таки не поле в базе данных, а объект хранящий ссылку на ключевое поле, т.е. какой-то дополнительный Id ВСЕГДА нужен
Здравствуйте, henson, Вы писали:
H>>>В EF кое-что могло бы быть упрощено если бы EntityObject уже содержал некий общий Id который все равно нужен в каждом дочернем объекте. G>>EntityKey?
H>EntityKey все-таки не поле в базе данных, а объект хранящий ссылку на ключевое поле, т.е. какой-то дополнительный Id ВСЕГДА нужен
Неверно. http://msdn.microsoft.com/ru-ru/library/system.data.entitykey(VS.90).aspx
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, henson, Вы писали:
H>>>>В EF кое-что могло бы быть упрощено если бы EntityObject уже содержал некий общий Id который все равно нужен в каждом дочернем объекте. G>>>EntityKey?
H>>EntityKey все-таки не поле в базе данных, а объект хранящий ссылку на ключевое поле, т.е. какой-то дополнительный Id ВСЕГДА нужен G>Неверно. http://msdn.microsoft.com/ru-ru/library/system.data.entitykey(VS.90).aspx
Что именно неверно? Как использовать EntityKey без внешнего ID ?
Здравствуйте, syomin, Вы писали:
S>Первичный ключ используется базой данных для однозначной идентификации строки в таблице. Поскольку задача ORM'а состоит в том, чтобы изолировать объекты предметной области от базы данных,
Не читайте Фаулера перед обедом.
"изолировать объекты предметной области от базы данных" — это задача Object Persistence Framework-ов, а не ORM. Задача ORM же намного проще — преобразовать реляционные данные (записи из таблиц) в списки объектов, тем самым упростив их обработку в ООЯ.
Так вот, Persistence Framework-и приводят к неоправданному оверхэду, при этом не давая реального повышения уровня абстрации.
S>то перечисленных выше полей быть не должно — достаточно просто ссылок. Думаю, технически это возможно. Другое дело, возможно ли это в EF.
Если тебе нужен Persistence Framework, то лучше выбрать Hibernate. Только потом не надо задавать вопрос "почему моё приложение так тормозит?".
G>>Потом сжечь все книги по ООП и выкинуть фаулера АКПП. S>Не конструктивно.
Последнее как раз конструктивно. Первое, конечно, перебор. Но вот доверять всему чему пишут в ООП-книгах нужно с оглядкой. ООП не панацея. Где-то он отлично ложится на задачу. Где-то он просто вреден или менее удобен.
Для обработки данных хранящихся в СУБД лучше подходит функциональный подход, а не ООП.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, syomin, Вы писали:
D>>Ну и как Ваш пользователь будете различать сотрудников у которых полностью одинаковые ФИО ? S>Зависит от условий задачи: дата рождения, место жительства, серия + номер паспорта и т.д. и т.п.
Это называется "составной первичный ключ".
S> Поймите простую вещь: если у нас первичный ключ является суррогатным, то в большинстве случаев никакого смысла показывать его пользователю нет, поэтому и тащить его в приложении дальше слоя доступа к базе данных не нужно.
А зачем пользователю то показывать? Скрывай его. Но в той же форме его держать надо, чтобы потом было по чему обновлять данные. (Хотя я не раз видел как люди запоминали свои номера и потом быстро по ним идентифицировались.)
Смотри какая фигня получается. Скрыв идентификатор в объекте и пытаясь идентифицировать что-то самим экземпляром объекта ты будешь вынужден сделать объект уникальным. Это резко усложняет работу с ним. Ты вынужден гарантировать, что данные в этом объекте синхронны данным в БД и то, что объект один. Это же означает, что такой же объект в другом процессе уже заводить чревато.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, syomin, Вы писали:
G>>Ну тогда тебе остается только свой ORM писать, покажи потом что получилось. S>Проще победить чувство прекрасного...
Если действительно достаточно загрузить сразу в память все данные, покрутить их там и сбросить на диск, то вам ни ОРМ ни БД даром не нудны: созраняйте в бинарник или в хмл на диск. Если нужна БД, то такой "ОРМ" делается за пол-дня/день, что совсем не дорого На крайняк можно в той же БД хранить граф в хмл. В таком случае просто EF — это молоток в ситуации, когда нужны пасатижы (здесь).
А вот как только [если] вам понадобится не "целый граф", а постепенное вытягиание сущностей, сохранение с обновлением, а не перезаписыванием, то иметь в какой-либо форме ижентификатор в объекте, с которым происходит работа пользователя придётся.
Help will always be given at Hogwarts to those who ask for it.