Adodb

Дополнительные вопросы разработки веб-приложений с доступом к данным

Чтобы при обслуживании веб-приложений, доступ к данным которых одновременно осуществляют более 10 пользователей, обеспечить высокое быстродействие и надежность работы, настоятельно рекомендуем использовать обработчик баз данных типа «клиент-сервер». Хотя интерфейс ADO работает с любым источником данных, совместимым со стандартом OLE DB, он был разработан и лучше всего проверен для работы с базами данных типа «клиент-сервер», такими как Microsoft SQL Server или Oracle.

Страницы ASP поддерживают в качестве допустимых источников данных базы данных с общими файлами (Microsoft Access или Microsoft FoxPro). Хотя некоторые примеры в документации ASP используют базу данных с общим файлом, желательно использовать обработчики таких типов баз данных только для средств разработки или для ограниченных сценариев развертывания. Базы данных с общими файлами могут хуже подходить для профессионально разработанных веб-приложений, которые должны обслуживать большое число запросов, по сравнению с базами данных типа «клиент-сервер».

При разработке ASP-приложения с доступом к базам данных, предназначенного для подключения к удаленной базе данных на SQL Server, следует иметь представление о приведенных ниже вопросах.

  • Выбор схемы подключения для SQL Server. Имеется возможность выбрать один из двух методов доступа к удаленной базе данных SQL Server: соединители TCP/IP и именованные каналы. Для именованных каналов проверка подлинности клиентов баз данных должна выполняться с помощью Windows перед установкой подключения. При этом имеется возможность, что удаленный компьютер, на котором запущены именованные каналы, откажет в доступе пользователю, имеющему необходимые учетные сведения для доступа к SQL Server, но не имеющему учетной записи пользователя Windows на данном компьютере. Напротив, подключения с помощью соединителей TCP/IP напрямую соединяются с сервером баз данных, без использования промежуточного компьютера, как при использовании именованных каналов. И поскольку подключения, выполненные с помощью соединителей TCP/IP соединяются напрямую с сервером баз данных, пользователи могут получить доступ через проверку подлинности SQL Server, а не через проверку подлинности Windows.
  • Ошибка ODBC 80004005. Если схема подключения для доступа к SQL Server задана неправильно, пользователи, просматривающие приложение с доступом к базам данных, могут получить сообщение об ошибке ODBC 80004005. Для исправления ситуации попробуйте использовать вместо сетевых подключений локальные подключения через именованный канал, если SQL Server запущен на том же компьютере, что и службы IIS. Правила безопасности Windows 2000 не будут использованы, поскольку канал является локальным, а не сетевым подключением, которое может олицетворяться с помощью учетной записи анонимного пользователя. Крое того, в строке подключения к SQL Server (либо в файле Global.asa, либо в сценарии страничного уровня) измените параметр SERVER=имя сервера на SERVER=(local). Ключевое слово (local) является специальным параметром, распознаваемым ODBC драйвером SQL Server. Если это решение не работает, попробуйте использовать протокол без проверки подлинности для связи между IIS и SQL Server, например соединители TCP/IP. Этот протокол будет работать при локальном запуске SQL Server или на удаленном компьютере.

Примечание.   Для увеличения быстродействия при подключении к удаленным базам данных воспользуйтесь соединителями TCP/IP.

Безопасность SQL Server. При использовании встроенных или смешанных средств безопасности SQL Server и при размещении базы данных SQL Server на удаленном сервере невозможно использование встроенной проверки подлинности Windows. Специфика заключается в том, что невозможно пересылать учетные сведения для встроенной проверки подлинности Windows на удаленный компьютер. Это означает, что может потребоваться использовать обычную проверку подлинности, при которой требуется ввод имени пользователя и пароля.

Для получения дополнительных сведений по этим вопросам посетите веб-узел Microsoft Product Support Services по адресу http://www.microsoft.com/support/.

Announcements

Follow us on @ADOdb_announce on Twitter. We post notices of new releases and important bug fixes first there.

Date Description
08/02/2022 ADOdb version 5.22.0 IS available. Full Changelog
22/01/2022 ADOdb versions 5.20.21 and 5.21.4 are available. Full Changelog
31/10/2021 ADOdb version 5.21.3 is available. Full Changelog
22/08/2021 ADOdb version 5.21.2 is available. Full Changelog
15/08/2021 ADOdb version 5.21.1 is available. Full Changelog
27/02/2021 ADOdb version 5.21.0 is available. Full Changelog
02/02/2021 ADOdb version 5.21.0-rc.1 is available. Full Changelog
31/01/2021 ADOdb version 5.20.20 available. Full Changelog
20/12/2020 ADOdb version 5.21.0-beta.1 is available. Full Changelog
13/12/2020 ADOdb version 5.20.19 is available. Full Changelog
28/06/2020 ADOdb version 5.20.18 is available. Full Changelog
31/03/2020 ADOdb version 5.20.17 is available. Full Changelog
12/01/2020 ADOdb version 5.20.16 is available. Full Changelog
24/11/2019 ADOdb version 5.20.15 is available. Full Changelog
06/01/2019 ADOdb version 5.20.14 is available. Full Changelog
06/08/2018 ADOdb version 5.20.13 is available. Full Changelog
30/03/2018 ADOdb version 5.20.12 is available. Full Changelog
Note that 5.20.11 has been withdrawn due to a bug on PHP 5.x
08/03/2018 ADOdb version 5.20.10 is available. Full Changelog
21/12/2016 ADOdb version 5.20.9 is available. Full Changelog
17/12/2016 ADOdb version 5.20.8 is available. Full Changelog
20/09/2016 ADOdb version 5.20.7 is available. Full Changelog
31/08/2016 ADOdb version 5.20.6 is available. Full Changelog
10/08/2016 ADOdb version 5.20.5 is available. Full Changelog
09/04/2016 ADOdb version 5.20.4 is available. Full Changelog
01/01/2016 ADOdb version 5.20.3 is available. Full Changelog
27/12/2015 ADOdb version 5.20.2 is available. Full Changelog
06/12/2015 ADOdb version 5.20.1 is available. Full Changelog
28/11/2015 ADOdb version 5.20.0 is available. Full Changelog

Наследование

Наследование является важным аспектом парадигмы объектно-ориентированного программирования, которая позволяет наследовать свойства и методы других классов, расширяя их. Класс, который наследуется, называется родительским классом, а класс, который наследует другой класс, называется дочерним классом.  Когда вы создаете экземпляр объекта дочернего класса, он также наследует свойства и методы родительского класса.

Давайте посмотрим на следующий скриншот, чтобы понять концепцию наследования.

В примере выше класс является родительским классом, а класс Employee расширяет или наследует класс , поэтому и называется дочерним классом.

Давайте попробуем разобраться на реальном примере, чтобы понять, как это работает.

Здесь важно отметить, что класс использовал для наследования класса  ключевое слово. Теперь класс может получить доступ ко всем свойствам и методам класса , объявленные как public или protected

(Он не может получить доступ к ntv, которые объявлены как private.)

В примере выше объект может получить доступ к методам и , которые определены в классе , поскольку они объявлены как public.

Затем мы обратились к методу , используя метод , определенный в классе , поскольку он объявлен как protected. Наконец, объект не может получить доступ к методу класса Person, поскольку он объявлен как .

С другой стороны, вы можете использовать объект для установки свойства класса , как мы это делали в методе , который определен в классе , поскольку свойство объявлено как protected.

И так, это было краткое введение в наследование. Оно помогает сократить дублирование кода и, следовательно, способствует его повторному использованию.

5 последних уроков рубрики «PHP»

Когда речь идёт о безопасности веб-сайта, то фраза «фильтруйте всё, экранируйте всё» всегда будет актуальна. Сегодня поговорим о фильтрации данных.

Обеспечение безопасности веб-сайта — это не только защита от SQL инъекций, но и протекция от межсайтового скриптинга (XSS), межсайтовой подделки запросов (CSRF) и от других видов атак

В частности, вам нужно очень осторожно подходить к формированию HTML, CSS и JavaScript кода.

Expressive 2 поддерживает возможность подключения других ZF компонент по специальной схеме. Не всем нравится данное решение

В этой статье мы расскажем как улучшили процесс подключение нескольких модулей.

Предположим, что вам необходимо отправить какую-то информацию в Google Analytics из серверного скрипта. Как это сделать. Ответ в этой заметке.

Подборка PHP песочниц
Подборка из нескольких видов PHP песочниц. На некоторых вы в режиме online сможете потестить свой код, но есть так же решения, которые можно внедрить на свой сайт.

Оператор parent

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

Чтобы вызвать нужный метод из родительского класса, вам понадобится обратиться к самому этому классу через дескриптор. Для этой цели в PHP предусмотрено ключевое слово parent. Оператор parent позволяет подклассам обращаться к методам (и конструкторам) родительского класса и дополнять их существующую функциональность. Чтобы обратиться к методу в контексте класса, используются символы «» (два двоеточия). Синтаксис оператора :

parent::метод_родительского_класа

Эта конструкция вызовет метод, определенный в суперклассе. Вслед за таким вызовом можно поместить свой программный код, который добавит новую функциональность:

<?php
  
  class book {
    public $title;
	public $price;
	
	function __construct($title, $price) {
	  $this->title = $title;
	  $this->price = $price;
	}
  }
  
  class new_book extends book {
    public $pages;
	
	function __construct($title, $price, $pages) {
	  // вызываем метод-конструктор родительского класса
	  parent::__construct($title, $price);
	  
	  // инициализируем свойство определенное в подклассе
	  $this->pages = $pages;
	}
  }
  
  $obj = new new_book('азбука', 35, 500);
  
  echo "Книга: $obj->title<br>
        Цена: $obj->price<br>
		Страниц: $obj->pages";
  
?>

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

Ключевое слово можно использовать не только в конструкторах, но и в любом другом методе, функциональность которого вы хотите расширить, достигнуть этого можно, вызвав метод родительского класса:

<?php
  
  class Cat {
    public $name = "Арни";
	
    function getstr() {
	  $str = "Имя кота: {$this->name}.";
	  return $str;
	}
  }
  
  class my_Cat extends Cat {
    public $age = 5;
	
	function getstr() {
	  $str = parent::getstr();
	  
	  $str .= "<br>Возраст: {$this->age} лет.";
	  return $str;
	}
  }
  
  $obj = new my_Cat;
  echo $obj->getstr();
  
?>

Здесь сначала вызывается метод из суперкласса, значение которого присваивается переменной, а после этого выполняется остальной код определенный в методе подкласса.

Теперь, когда мы познакомились с основами наследования, можно, наконец, рассмотреть вопрос видимости свойств и методов.

Ответ 3

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

Если вы «кодируете интерфейс, а не реализацию», то обычно довольно просто принимать решения о видимости. В общем, переменные должны быть закрытыми или защищенными, если у вас нет веских причин для их раскрытия. Вместо этого используйте общедоступные методы доступа (геттеры/сеттеры) для ограничения и регулирования доступа к внутренним компонентам класса.

Если использовать автомобиль в качестве аналогии, такие вещи, как скорость, передача и направление, будут частными переменными экземпляра. Вы же не хотите, чтобы водитель напрямую управлял такими вещами, как соотношение воздух/топливо. Вместо этого вы предоставляете ограниченное количество действий как общедоступные методы. Интерфейс автомобиля может включать в себя методы, такие как accelerate(), deccelerate()brake(), setGear(), turnLeft(), turnRight() и т. д.

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

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

Принцип единственной ответственности

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

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

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

Посмотрите на пример плохо спреэктированного класса:

А в контроллере этот класс вызывается как-то так:

В классе , сходу можно увидеть основную проблему, которая связана с тем, что этот класс имеет слишком много обязанностей:

  • Проверка аутентификации пользователя.
  • Устанавливает подключение к базе данных, и выполняет sql запросы, работая с подключением напрямую.
  • Один метод совмещает в себе 2 обязанности: по отображению поста и по его редактированию (если $POST заполнен)
  • Отображает html-код поста и формы редактирования внутри метода.

Вместо этого, любой из классов должен иметь только по одной обязанности

Потому, сейчас перепишем этот класс с учётом новых требований.

  • При работе с базой данных я предпочитаю использовать классы-репозитории, которые внутри себя подключаются к базе данных и выполняют все запросы.
  • Проверка аутентификации должна производиться в контроллере, а не внутри этого класса (как вариант использования — проверку аутентификации пользователя можно вынести в middleware, или в правила конфигурации маршрутов).
  • Отображение вёрстки вынесем в отдельные файлы представлений.

В коде появился новый класс — , который в конструктор принимает класс подключения к базе данных (условно, скажем, что это объект ), который позволяет выполнять к ней запросы. И теперь только класс отвечает за всю работу с базой данных, касаемо статей, исключая работу с запросами к БД из контроллера напрямую.

Другое изменение было применено к проверке аутентификации пользователя. Эта обязанность была вынесена в контроллер, где ему и место.

А так же, вся разметка была вынесена из класса в отдельный файл представлений, и подключается функцией .

Так же, и код самого контроллера был немного изменён. Теперь контроллер имеет 2 метода для 2 разных задач. Эти методы получают пост по идентификатору (с помощью ), а после — отображают представление, в зависимости от того, отображается этот пост, или редактируется. В отличии же, от того, что было ранее, когда один метод отправлял все данные объекту , который сам занимался отображением контенета.

Новая версия выглядит на порядок чище, проще для тестирования, и обновления.

Из этого примера, я надеюсь, стало понятно, что класс должен иметь только одну обязанность (при изменении одной части кода в классе, эти изменения должны повлиять на весь код, где этот класс используется). К примеру, при обновлении метода класса , изменив драйвер подключения к БД, новые изменения будут применены ко всему коду, где этот класс был задействован. В отличии от того, когда запросы к базе данных писались нативно. И, при необходимость замены драйвера подключения, или синтаксиса запросов, пришлось бы править каждый файл, где этот код написан.

Модернизация ADODB

Вы вполне можете хотеть изменить ADODB под свои собственные нужды. К счастью, вы легко можете поддерживать обратную совместимость расширяя ADODB и используя переменную $ADODB_NEWCONNECTION. $ADODB_NEWCONNECTION позволяет перекрыть поведение ADONewConnection(). ADONewConnection() проверяет эту переменную и вызывает функцию с именем, сохраненным в этой переменной.

В следующем примере, новые функциональные возможности для объекта соединения помещены в классы hack_mysql и hack_postgres7. Название классов (навязанные соглашения) для обработки данных контролируются при помощи переменной $rsPrefix. Здесь мы устанавливаем ее в ‘hacks_rs_’, это заставит ADODB использовать hacks_rs_mysql и hacks_rs_postgres7 как классы для обработки данных.

class hack_mysql extends adodb_mysql {
var $rsPrefix = 'hack_rs_';
/* Ваши изменения здесь */
}
class hack_rs_mysql extends ADORecordSet_mysql {
/* Ваши изменения здесь */
}
class hack_postgres7 extends adodb_postgres7 {
var $rsPrefix = 'hack_rs_';
/* Ваши зменения здесь */
}
class hack_rs_postgres7 extends ADORecordSet_postgres7 {
/* Ваши изменения здесь */
}
$ADODB_NEWCONNECTION = 'hack_factory';
function& hack_factory($driver)
{
if ($driver !== 'mysql' && $driver !== 'postgres7') return false;
$driver = 'hack_'.$driver;
$obj = new $driver();
return $obj;
}
include_once('adodb.inc.php');

Незабудьте вызывать конструктор родительского класса из вашего конструктора. Если вы хотите использовать драйвер ADODB поумолчанию — верните FALSE из hack_factory().

А что же дальше?

Думаю, что можно вас поздравить — у вас все настроено и работает! Какие же следующие шаги? Все зависит от того, зачем вам нужно было организовывать доступ к базе — для обмена информацией с корпоративным сайтом, для работы мобильного приложения, для связки с корпоративным ПО…

Если требуется сделать на сайте что-то типа кабинета пользователя с предоставлением истории взаиморасчетов, действующих цен с учетом персональных скидок, ввода заказа и прочими плюшками, то к нашим услугам есть несколько готовых библиотек на официальном сайте. Есть даже целый фреймворк OpenUI5 от компании SAP, который на базе данных получаемых по протоколу OData позволяет создать полноценное бизнес-приложение. В общем, раздолье для грамотного JS-программиста.

Допустим, что мы не грамотные JS-программисты, но какой-то списочек повесить на сайт хотим. Я открыл статью с перечнем самых популярных на сегодняшний день библиотек создания таблиц и нашел в нем простенькую библиотечку jsGrid как раз для нашего случая. Изучаем их сайт, берем пример их кода по использованию OData и вставляем туда путь к нашим данным.

Что бы совсем быть ленивым и ничего не программировать для нашего примера, мне нужно запросить полноценную табличку без необходимости по ссылкам догружать строковые представления. В типовой УТ10.3 на этот счет выбор не очень богатый и потому я возьму справочник Контрагенты.

Теперь самое интересное. А как же сформировать строку запроса на чтение нужных нам данных? Это просто! Смотрим по нашему пути к корню OData (для меня это http://localhost/DemoTrdBase/odata/standard.odata/) как правильно называется этот справочник — Catalog_Контрагенты. Далее открыв в новом окне адрес http://localhost/DemoTrdBase/odata/standard.odata/Catalog_Контрагенты мы увидим содержимое всего справочника в формате XML. Но для нашего примера нужен JSON и потому к строке нужно добавить параметр: $format=json — получится http://localhost/DemoTrdBase/odata/standard.odata/Catalog_Контрагенты?$format=json. Так, группы нам не интересны и давайте их уберем с помощью параметра фильтрации: $filter=IsFolder eq false — получится http://localhost/DemoTrdBase/odata/standard.odata/Catalog_Контрагенты?$format=json&$filter=IsFolder eq false. Блок параметров, как вы уже заметили начинается символом «?», а сами параметры между собой соединяются символом «&». Полный список доступных параметров и функций смотрите в документации по платформе.

Полученный файл положим в каталог, который настроен корневым в вашем веб-сервере. Это необходимо, что бы «домены» странички и запрашиваемых данных совпадали, иначе получите бесконечный индикатор обновления и ошибку в логах: «No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘null’ is therefore not allowed access. The response had HTTP status code 401.»

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

Перегрузка методов с помощью __call()

Геттеры и сеттеры используются для запрета на доступ к частным переменным. В этом же направлении используется метод __call() для запрета доступа к частным методам. Как только из кода вызывается метод класса, который либо не существует, либо он недоступен, автоматически вызывается метод __call(). Вот общий синтаксис метода:

public function __call( $methodName, $arguments ) {
 // (действия)
}

Когда производится попытка вызвать недоступный метод класса, PHP автоматически вызывает метод __call(), в который передает строку — имя вызываемого метода и список передаваемых параметров в массиве. Затем ваш метод __call() должен будет определенным способом обработать вызов и, в случае необходимости, вернуть значения.

Метод __call() полезен в ситуациях, когда вам нужно передать некую функциональность класса другому классу. Вот простой пример:

class Member {

 private $username;

 public function __construct( $username ) {
   $this->username = $username;
 }

 public function getUsername() {
   return $this->username;
 }
}

class Topic {

 private $member;
 private $subject;

 public function __construct( $member, $subject ) {
   $this->member = $member;
   $this->subject = $subject;
 }

 public function getSubject() {
   return $this->subject;
 }

 public function __call( $method, $arguments ) {
   return $this->member->$method( $arguments );
 }
}

$aMember = new Member( "fred" );
$aTopic = new Topic( $aMember, "Hello everybody!" );
echo $aTopic->getSubject() . "<br>"; // отобразит "Hello everybody!"
echo $aTopic->getUsername() . "<br>"; // отобразит "fred"

Данный пример похож на тот, что приводился в разделе о явном указании типов. У нас есть класс Member с полем $username и класс Topic с полем — объектом класса Member (автор статьи) и полем $subject — темой статьи. Класс Topic содержит метод getSubject() для получения темы статьи, но в нем нет метода, который возвращал бы имя автора статьи. Вместо него в нем есть метод __call(), который вызывает несуществующий метод и передает аргументы методу класса Member.

Когда в коде вызывается метод $aTopic->getUsername(), PHP понимает, что такого метода в классе Topic не существует. Поэтому вызывается метод __call(), который в свою очередь, вызывает метод getUsername() класса Member. Этот метод возвращает имя автора методу __call(), а тот отправляет полученное значение вызывающему коду.

На заметку: в PHP есть и другие методы, касающиеся перегрузки, например, __isset(), __unset(), и __callStatic().

Конфигурация отношений One-to-Many

В этом разделе мы узнаем, как создавать отношения «один ко многим» всеми тремя способами. Итак, прежде чем мы начнем, давайте создадим дополнительный класс модели в проекте :

Использование условного подхода для создания отношений «один ко многим»

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

Первый подход включает свойство навигации в основной сущности, классе :

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

Еще один способ создать связь «один ко многим» — это добавить свойство в класс без свойства ICollection в классе Student класс:

Чтобы этот подход работал, мы должны добавить свойство в класс .

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

Это результат любого из этих трех подходов:

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

Если мы хотим создать требуемую связь между сущностями и , мы должны включить внешний ключ в класс . :

Теперь, когда мы выполним нашу миграцию, мы увидим следующий результат:

Очевидно, что наши отношения сейчас необходимы.

Подход с аннотациями данных

Подход с использованием аннотаций к данным содержит только два атрибута, связанных с отношениями. Атрибуты и .

Атрибут позволяет нам определять внешний ключ для свойства навигации в классе модели. Итак, давайте изменим класс , добавив этот атрибут:

Мы применили атрибут поверх свойства (которое является внешним ключом в этом классе), присвоив ему имя свойства навигации . Но работает и наоборот:

Атрибут ForeignKey принимает один параметр строкового типа. Если внешний ключ является составным ключом, атрибут ForeignKey должен выглядеть следующим образом:

.

Какой бы способ мы ни выбрали, результат будет таким же, как и при подходе «по соглашению». Мы собираемся создать требуемую связь между этими двумя таблицами:

Подход Fluent API для конфигурации One-to-Many

Чтобы создать отношение «один ко многим» с этим подходом, нам нужно удалить атрибут из класса и изменить , добавив этот код:

builder.HasMany(e => e.Evaluations)
    .WithOne(s => s.Student)
    .HasForeignKey(s => s.StudentId);

Результат будет таким же:

Здесь нужно упомянуть одну вещь.

Для модели базы данных, такой как мы определили, нам не нужен метод . Это потому, что свойство внешнего ключа в классе Evaluation имеет тот же тип и то же имя, что и первичный ключ в классе Student. Это означает, что по Конвенции это отношение все равно будет обязательным. Но если бы у нас был внешний ключ с другим именем, например StudId, тогда понадобился бы метод , потому что в противном случае ядро EF создало бы необязательную связь между классами Evaluation и Student.

Чтение записей

//*******************************************
Процедура Сформировать()
    //Открываем соединение
    ado.Open("Driver={Microsoft Access Driver (*.mdb)};Dbq="+ф_ИмяMDB+";Uid=Admin;Pwd=;");
    
    таб=СоздатьОбъект("Таблица");
    таб.ИсходнаяТаблица("Таблица");
    таб.ВывестиСекцию("Шапка");
    таб.Опции();
    
    
     Запрос="SELECT * FROM ТестоваяТаблица;";
    ado.Execute(Запрос);
    
    Пока ado.EOF= Цикл //Цикл по записям 
        таб.ВывестиСекцию("Строка|Начало");
        зн=ado.GetField("id"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("text1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("memo1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Байт1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Целое1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("ДлинноеЦелое1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Single1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Double1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("КодРепликации1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("ДатаВремя1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetFieldAsDateTime("ДатаВремя1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Денежный1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Логический1"); таб.ПрисоединитьСекцию("Строка|Данные");
        зн=ado.GetField("Действительное1"); таб.ПрисоединитьСекцию("Строка|Данные");
        ado.MoveNext(); //Переходим к след. записи 
    КонецЦикла;

  ado.Close(); //Закрываем соединение
  таб.Показать("Запрос");
КонецПроцедуры
Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: