Форум программистов, компьютерный форум, киберфорум
C#: Базы данных, ADO.NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.82/11: Рейтинг темы: голосов - 11, средняя оценка - 4.82
0 / 0 / 0
Регистрация: 23.04.2021
Сообщений: 4
1

EF Добавление данных в таблицу DataGrid со внешним ключом через другую форму

23.04.2021, 19:42. Показов 2295. Ответов 7

Author24 — интернет-сервис помощи студентам
Всем привет. Пишу курсовую работу и столкнулась с крайне сложной задачей (для меня) — осуществить добавление данных в таблицу, содержащую сразу два внешних ключа. При попытке добавить всплывает следующее исключение:
SqlException: Конфликт инструкции INSERT с ограничением FOREIGN KEY "FK_Заказы_Заказчики". Конфликт произошел в базе данных "Марк-Трейдинг", таблица "dbo.Заказчики", column 'ИдЗак'.
Выполнение данной инструкции было прервано.


Суть этого исключения мне понятна: не осуществляется заполнение поля таблицы в БД "ИдЗак" (айди заказчика из др. таблицы). Пыталась избежать этого при помощи такой строчки кода, однако исключение повторилось:

C#
1
            int idZakaz = context.Заказчики.Where(b => b.НаимОрганизации == CBNaim.SelectedItem.ToString()).FirstOrDefault().ИдЗак;
Так вот, хотелось бы понять и узнать, что нужно в таком случае прописать, дабы шло заполнение поля "ИдЗак" в самой БД, а у меня в самой DataGrid на основной форме отображались наименования организаций, взятые из таблицы "Заказчиков". В случае, если какой-то информации не достает, пожалуйста, запросите, сразу всё предоставлю.

Xaml код основной формы:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Grid>
        <Grid Background="White">
            <Grid.RowDefinitions>
                <RowDefinition ></RowDefinition>
                <RowDefinition Height="70"></RowDefinition>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="1" Orientation="Horizontal">
                <Button FontFamily="Arial" FontSize="14" Width="100" Height="40" Click="ButtonAdd">Добавить</Button>
                <Button FontFamily="Arial" FontSize="14" Width="100" Height="40" Margin="10" Click="ButtonDel">Удалить</Button>
 
            </StackPanel>
 
            <StackPanel>
                <DataGrid AutoGenerateColumns="False" ColumnWidth="*" x:Name="GridJurZak">
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="№" Binding="{Binding НомерЗаказа}"></DataGridTextColumn>
                        <DataGridTextColumn Header="Наименование организации" Binding="{Binding Заказчики.НаимОрганизации}"></DataGridTextColumn>
                        <DataGridTextColumn Header="Отход" Binding="{Binding Отходы.Наименование}" ></DataGridTextColumn>
                        <DataGridTextColumn Header="Объём" Binding="{Binding ОбъёмВТоннах}"></DataGridTextColumn>
                        <DataGridTextColumn Header="Дата" Binding="{Binding Дата, StringFormat={}{0:dd.MM.yy}}"></DataGridTextColumn>
                        
                    </DataGrid.Columns>
 
                </DataGrid>
            </StackPanel>
        </Grid>
 
    </Grid>
С# код основной формы:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public partial class Журнал_заказов : Page
    {
        MTEntities context = new MTEntities();
        public Журнал_заказов()
        {
            InitializeComponent();
            context = new MTEntities();
 
            GridJurZak.ItemsSource = context.Заказы.ToList();
        }
 
        private void ButtonAdd(object sender, RoutedEventArgs e)
        {
            var newZakaz = new Заказы();
            context.Заказы.Add(newZakaz);
            var x = new ДобавлениеЗаказа(context, newZakaz);
            x.ShowDialog();
            GridJurZak.ItemsSource = context.Заказы.ToList();
        }
 
        private void ButtonDel(object sender, RoutedEventArgs e)
        {
            var q = GridJurZak.SelectedItem as Заказы;
            if (q == null)
            {
                MessageBox.Show("Эта строка и так пустая.");
                return;
            }
            MessageBoxResult result = MessageBox.Show("Вы действительно хотите удалить строку?", "Удалить?", MessageBoxButton.YesNoCancel);
            if (result == MessageBoxResult.Yes)
            {
                context.Заказы.Remove(q);
                context.SaveChanges();
                GridJurZak.ItemsSource = context.Заказы.ToList();
            }
        }
    }
Xaml код формы добавления заказа:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel Background="#FF4DA866" VerticalAlignment="Center" Orientation="Vertical" Grid.RowSpan="3">
            <TextBlock HorizontalAlignment="Center" FontFamily="Arial" FontSize="14" Margin="15" >Номер заказа:</TextBlock>
            <TextBlock HorizontalAlignment="Center" FontFamily="Arial" FontSize="14" Margin="13">Наименование организации:</TextBlock>
            <TextBlock HorizontalAlignment="Center" FontFamily="Arial" FontSize="14" Margin="15">Отход:</TextBlock>
            <TextBlock HorizontalAlignment="Center" FontFamily="Arial" FontSize="14" Margin="12">Объём:</TextBlock>
            <TextBlock HorizontalAlignment="Center" FontFamily="Arial" FontSize="14" Margin="12">Дата:</TextBlock>
            
        </StackPanel>
        <StackPanel Background="#FF4DA866" VerticalAlignment="Center" Orientation="Vertical" Grid.RowSpan="3" Grid.Column="1">
            <TextBox Text="{Binding НомерЗаказа}" x:Name="TBNumb" HorizontalAlignment="Center" Margin="9" Width="250" Height="25"></TextBox>
            <ComboBox  SelectedItem="{Binding Заказчики.НаимОрганизации}" x:Name="CBNaim" HorizontalAlignment="Center" Margin="9" Width="250"></ComboBox>
            <ComboBox SelectedItem="{Binding Отходы.Наименование}" x:Name="CBOth" HorizontalAlignment="Center" Margin="9" Width="250"></ComboBox>
            <TextBox Text="{Binding Объём}" x:Name="TBOb" HorizontalAlignment="Center" Margin="9" Width="250" Height="25"></TextBox>
            <DatePicker SelectedDate="{Binding Дата}" x:Name="DPData" HorizontalAlignment="Center" Margin="9" Width="250" Height="25"></DatePicker>
            
        </StackPanel>
        <StackPanel Grid.RowSpan="3" Grid.Row="3" Grid.ColumnSpan="2" VerticalAlignment="Center">
            <Button Click="ButtonAdd" FontFamily="Arial" FontSize="14" Width="100" Height="30" Margin="20">Добавить</Button>
            <Button Click="ButtonClose" FontFamily="Arial" FontSize="14" Width="100" Height="30">Закрыть</Button>
        </StackPanel>
 
    </Grid>
С# код формы добавления заказа:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public partial class ДобавлениеЗаказа : Window
    {
        MTEntities context;
        public ДобавлениеЗаказа(MTEntities context, Заказы newZakaz)
        {
            InitializeComponent();
            this.context = context;
            
            foreach(var Zakaz in context.Заказчики.ToList())
            {
                CBNaim.Items.Add(Zakaz.НаимОрганизации.ToString()); //вывод значений столбца наименований организаций в combobox
               
                
            }
            foreach (var Othod in context.Отходы.ToList())
            {
                CBOth.Items.Add(Othod.Наименование.ToString());//вывод значений столбца наименований отходов в combobox
            }
            this.DataContext = newZakaz;
           
        }
 
        private void ButtonAdd(object sender, RoutedEventArgs e)
        {
            int idZakaz = context.Заказчики.Where(b => b.НаимОрганизации == CBNaim.SelectedItem.ToString()).FirstOrDefault().ИдЗак;
            int idOth = context.Отходы.Where(r => r.Наименование == CBOth.SelectedItem.ToString()).FirstOrDefault().ИдОтхода;
 
            context.SaveChanges();
            this.Close();
        }
 
        private void ButtonClose(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.04.2021, 19:42
Ответы с готовыми решениями:

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

Добавление данных в таблицу через форму
Здраствуйте, помогите пожалуйста: Необходимо, чтобы введенные данные в пустые поля на форме...

Добавление данных в таблицу sql через форму
Здравствуйте! Подскажите пожалуйста как записать данные в таблицу sql через форму c#. Т.e. есть три...

Добавление данных через форму в таблицу базы данных MS SQL
Здравствуйте! Я делаю форму для добавления записи в таблицу базы данных, созданную в MS SQL...

7
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
23.04.2021, 20:59 2
Опять кириллица, Вас что, в одной бурсе всех учат ?

По сути:
У Вас баг на баге, по сути везде. Например, по кнопке "Добавить" осн.формы Вы зачем-то создаете новый экземпляр модели "Заказ". Пустой. Затем открываете форму для заполнения полей, из которых предполагаете перенести данные в эту модель. Само по себе идиотизм, извините. При этом передать указатель на созданную только что модель не удосужились.
В какую модель будет заносить данные Ваша вторая форма ? IF сам разберется в Ваших путанных мыслях ?
Поехали дальше.
Вторая форма по кнопке "Добавить" Ищутся id выбранных в комбобоксах CBNaim и CBOth (что они содержат, можно только догадываться) и кладутся в переменные. При этом никакой проверки на Null (если не найдено) не делается. А, да ладно, для курсача сойдет . Допустим, выбрали. не null. И ? Что дальше ? Сразу даем SaveChanges ВСЕМУ контексту !!!
Надо полагать, что Вы рассуждали примерно так:
1. Я добавила в контекст новый экземпляр сущности "Заказ". EF это запомнил.
2. Я нашла id внешних ключей для того, чтобы записать их в новую сущность
3. Я даю команду "сохранить изменения". При этом EF должен взять созданный ранее экземпляр модели, проинициализировать самостоятельно все ее поля, затем догадаться, что в переменных IdZakaz и IdOth лежат нужные ссылки на справочники (а как иначе, ведь он сам же давал их по запросам к кому же контексту), вероятно потому, что они имеют такие же имена, как и поля-свойства модели, и все это аккуратно сохранить в базу.

Конгениально !, как сказал бы Остап

Добавлено через 6 минут
Покажите все классы модели
0
0 / 0 / 0
Регистрация: 23.04.2021
Сообщений: 4
23.04.2021, 21:20  [ТС] 3
Прошу прощения за то, что мой код написан настолько неумело — чему научили, то и пытаюсь реализовать :(
Правда, буду премного благодарна, если разъясните, как в моем случае можно выйти из ситуации и осуществить то, что требуется, каким-либо способом. Как-то улучшать код и делать его идеальным надобности нет (ведь, как я поняла, в таком варианте исхода событий нужно переделывать абсолютно всё :D)

Модель заказов:
C#
1
2
3
4
5
6
7
8
9
10
11
12
public partial class Заказы
    {
        public int ИдЗаказ { get; set; }
        public string НомерЗаказа { get; set; }
        public int ИдЗак { get; set; }
        public System.DateTime Дата { get; set; }
        public float ОбъёмВТоннах { get; set; }
        public int ИдОтхода { get; set; }
    
        public virtual Заказчики Заказчики { get; set; }
        public virtual Отходы Отходы { get; set; }
    }
Модель заказчиков:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public partial class Заказчики
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Заказчики()
        {
            this.Заказы = new HashSet<Заказы>();
        }
    
        public int ИдЗак { get; set; }
        public string НаимОрганизации { get; set; }
        public string Город { get; set; }
        public string Улица { get; set; }
        public string НомерДома { get; set; }
        public string НомерДоговора { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Заказы> Заказы { get; set; }
    }
Модель списка отходов:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 public partial class Отходы
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public Отходы()
        {
            this.Заказы = new HashSet<Заказы>();
            this.ПоставкиУслуг = new HashSet<ПоставкиУслуг>();
        }
    
        public int ИдОтхода { get; set; }
        public string Наименование { get; set; }
        public long Код_ФККО { get; set; }
        public decimal ЦенаЗаТонну { get; set; }
    
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Заказы> Заказы { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<ПоставкиУслуг> ПоставкиУслуг { get; set; }
    }
0
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
23.04.2021, 22:45 4
Надо:
1. Модель (содержимое папки Models), состоящее в общем случае из 2-х частей:
1. EF (папка .edmx), содержит два блока кода - классы моделей (декларация) и контекст (набор DBSet<T>) - имплементация
2. Расширение.
- Классы расширения. Содержат декларации классов - проекций наборов данных, полученных в результате выполнения запросов, не имеющих соответствующих сущностей в БД и, естественно, отсутствующих в папке .edmx. Нужны для выборок данных из нескольких таблиц или выборок с агрегатами.
- Репозиторий - статичный класс, реализующий весь функционал взаимодействия с БД. Содержит методы выборок, изменений в БД, в том числе с использование контекста EF. Его методы получают исходные данные как список параметров или ссылку на модель, возвращают набор данных (например для гридов) или Модель или списки для комбобоксов и т.д.

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

3. Вторичные формы.
Открываются модально для редактирования или правки текущей записи грида.
Получают от главной формы id активной записи грида или -1, ели новая запись.
Предоставляют элементы для внесения данных - TextBox, Datetimepicker, UpDown, Combobox т.д.
По событию Load три первых при редактировании заполняются данными из записи, найденной в EF по полученнному id методом FirstOrDefault контекста EF. При вставке чистятся. Последние заполняются из справочников (ссылочных таблиц) с помощью методов репозитория, возвращающих вместо моделей только id и наименования, которые содержатся в видимой части развернутого комбобокса.
Две кнопки "Сохранить" и "Отменить".

Добавлено через 1 минуту
Заметьте, пока мы не трогали контекст EF. Тем самым не вносили никаких правок в его кеш (а это ВАЖНО).

Добавлено через 2 минуты
В гриде главной формы лежат модели, не связанные с EF ибо получили их не через его контекст и модели, а через наше расширение. Т.е. EF ни разу не напрягся, а это хорошо

Добавлено через 14 минут
Вторичная форма.
По нажатию "Отмена" просто закрытие формы и возврат в грид. Ничего и нигде трогать не нужно. EF курит в стороне - и это хорошо.

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

Валидация прошла успешно - данные готовы для отправки на сервер.
Код формы обращается к соответствующему методу Репозитория, передавая ему введенные значения либо списком параметров либо через модель, предварительно создав ее и перенеся в нее данные из контролов.

Метод репозитория, получив данные, уже в контексте EF создает новую модель, заполняет ее полученными данными.
При этом, если был указан ключ или значение на вторичную таблицу-справочник, метод делает запрос к контексту EF, получая от него нужную модель EF (запись ссылочной таблицы) и результат помещает все в ту же модель (там, где ICollection). Итак, модель готова и заполнена, можно посмотреть ее содержимое в отладчике.
Вот теперь можно и нужно дать SaveChanges контексту EF. Сейчас он точно поймет что от него требуется и выполнит запись в БД.

После этого вторичная форма сигнализирует (кодом возврата) Главной форме, что добавления или изменение прошло успешно.

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

Добавлено через 2 минуты
Предваряю вопрос о том, как узнать id только что добавленной записи.
После SaveChanges можно извлечь новый Id из самой модели, куда его вложит EF. Вот этот Id и можно передать главной форме в качестве кода возврата.

Добавлено через 4 минуты
В результате Вы получаете приложение, в котором формы ничего не знают про БД, никаким образом не передают данные между собою (кроме разве что id) и никак не лазают друг дружке в контролы.
Также Вы имеете Модель, полностью реализующую всю логику работы с БД и никоим образом не зависящую от каких бы то ни было форм и контролов. Это значит, что Вы можете кромсать Ваш интерфейс как угодно, тасуя формы и контролы на них как колоду карт - работа с базой останется в стороне - ее не нужно будет править вообще.
0
0 / 0 / 0
Регистрация: 23.04.2021
Сообщений: 4
23.04.2021, 22:58  [ТС] 5
Огромное спасибо за то, что Вы так подробно все расписали. Пойду все разбирать и вникать, но, в случае чего, ожидайте кучу вопросов, скорее всего, и очень глупых в том числе.
0
MsGuns
24.04.2021, 12:19
  #6

Не по теме:

Umeco, Валяйте, помочь милой барышне - честь для благородного рыцаря :)
ЗЫ. Чтобы Ваша ветка была у меня в топах, упоминайте мой ник в сообщениях (щелчок на нике слева).

0
0 / 0 / 0
Регистрация: 23.04.2021
Сообщений: 4
24.04.2021, 14:27  [ТС] 7
MsGuns,
Цитата Сообщение от MsGuns Посмотреть сообщение
Код формы обращается к соответствующему методу Репозитория, передавая ему введенные значения либо списком параметров либо через модель, предварительно создав ее и перенеся в нее данные из контролов.
Метод репозитория, получив данные, уже в контексте EF создает новую модель, заполняет ее полученными данными.
При этом, если был указан ключ или значение на вторичную таблицу-справочник, метод делает запрос к контексту EF, получая от него нужную модель EF (запись ссылочной таблицы) и результат помещает все в ту же модель (там, где ICollection). Итак, модель готова и заполнена, можно посмотреть ее содержимое в отладчике.
Вот теперь можно и нужно дать SaveChanges контексту EF. Сейчас он точно поймет что от него требуется и выполнит запись в БД.
Хотелось бы побольше узнать касательно этой части, остальное, вроде как, понятно. Было бы хорошо привести конкретный пример кода, так как с теорией у меня более-менее, а вот как расписать всё на практике — довольно проблематично. Было бы круто также, если бы Вы обозначили какой-то конкретный материал, где это можно изучать поподробнее, ибо в нашем колледже не рассказывают ничего от слова совсем; всё должны познавать сами, в связи с чем и образуются подобные некрасивые кодики.
0
1497 / 1238 / 245
Регистрация: 04.04.2011
Сообщений: 4,363
24.04.2021, 17:32 8
Для начала:
https://metanit.com/sharp/articles/mvc/11.php
0
24.04.2021, 17:32
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
24.04.2021, 17:32
Помогаю со студенческими работами здесь

Перенос данных из трех таблиц DataGrid в другую таблицу DataGrid
Коллеги, всем добрый день!. Прошу у Вас помощи вот в таком вопросе. Я разрабатываю БД подход...

Добавление данных в таблицу через форму - не могу найти ошибку
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data;...

Добавление записи с внешним ключом в БД
Привет всем! Нужен совет, а то не получается кое-что. Такой трабл: есть две таблички - users и...

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

Добавление в таблицы объединенные внешним ключом
Пожалуйста, скажите, что не так???????

Добавить запись в таблицу с внешним ключом
Есть 3 таблицы: Category(idCategory, name), таблица Providers(idProviders, name, adress,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru