Возникли проблемы при вставке записей в локальную базу данных SQL с использованием EF 6 - PullRequest
0 голосов
/ 17 марта 2020

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

Программа использует локальную базу данных в моем проекте. Я использую Windows Forms, NET Framework 4.7.2 с EF6, моя база данных основана на сервисе, который вы можете добавить в Visual Studio.

Я создал форму, которая должна регистрировать клиентов, однако, когда я нажимаю кнопку, она не вставляет значения в базу данных, даже если вставки SQL работают нормально? Для базы данных установлен столбец ID с автоинкрементом, поэтому я просто пропускаю установку любого идентификатора в моих кодах, поскольку база данных должна генерировать его автоматически, верно?

Вот вывод SQL при запуске с некоторыми значениями теста:

Opened connection at 17/03/2020 17:30:34 -03:00

SELECT Count(*)
FROM INFORMATION_SCHEMA.TABLES AS t
WHERE t.TABLE_SCHEMA + '.' + t.TABLE_NAME IN ('dbo.Clientes')
    OR t.TABLE_NAME = 'EdmMetadata'
-- Executing at 17/03/2020 17:30:34 -03:00
-- Completed in 39 ms with result: 1

Closed connection at 17/03/2020 17:30:34 -03:00
"ZyonCliente.exe" (CLR v4.0.30319: ZyonCliente.exe): Carregado "C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Runtime.Serialization\v4.0_4.0.0.0__b77a5c561934e089\System.Runtime.Serialization.dll". Carregamento de símbolos ignorado. O módulo está otimizado e a opção do depurador 'Apenas Meu Código' está habilitada.
Opened connection at 17/03/2020 17:30:35 -03:00
SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[__MigrationHistory] AS [Extent1]
        WHERE [Extent1].[ContextKey] = @p__linq__0
    )  AS [GroupBy1]
-- p__linq__0: 'ZyonCliente1.DAL.ContextoBancoDeDados' (Type = String, Size = 4000)
-- Executing at 17/03/2020 17:30:35 -03:00
-- Failed in 13 ms with error: Invalid object name 'dbo.__MigrationHistory'.

Closed connection at 17/03/2020 17:30:35 -03:00
Opened connection at 17/03/2020 17:30:35 -03:00
SELECT 
    [GroupBy1].[A1] AS [C1]
    FROM ( SELECT 
        COUNT(1) AS [A1]
        FROM [dbo].[__MigrationHistory] AS [Extent1]
    )  AS [GroupBy1]
-- Executing at 17/03/2020 17:30:35 -03:00
-- Failed in 6 ms with error: Invalid object name 'dbo.__MigrationHistory'.

Closed connection at 17/03/2020 17:30:35 -03:00
"ZyonCliente.exe" (CLR v4.0.30319: ZyonCliente.exe): Carregado "EntityFrameworkDynamicProxies-EntityFramework". 
Opened connection at 17/03/2020 17:30:35 -03:00
Started transaction at 17/03/2020 17:30:35 -03:00
INSERT [dbo].[Clientes]([Nome], [Endereco], [Data_de_Nascimento], [Email], [Telefone])
VALUES (@0, @1, @2, @3, @4)
SELECT [ID]
FROM [dbo].[Clientes]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()
-- @0: 'testname' (Type = String, Size = 50)
-- @1: 'testaddress' (Type = String, Size = 100)
-- @2: '25/02/2020 17:30:17' (Type = DateTime2)
-- @3: 'testemail' (Type = String, Size = 80)
-- @4: 'testphone' (Type = String, Size = 50)
-- Executing at 17/03/2020 17:30:35 -03:00
-- Completed in 13 ms with result: SqlDataReader

Committed transaction at 17/03/2020 17:30:35 -03:00
Closed connection at 17/03/2020 17:30:35 -03:00

Я пробовал несколько различных методов, даже создавая новый проект на основе этой же базы данных, но вставляя значения с помощью метода прямой вставки (вместо использования шаблона UnitsOfWork) и как хорошо используя компонент BindingSource для обработки вставки, ничего не работает, и я не знаю почему, потому что кажется, что SQL работает, но база данных просто отказывается обновляться?

Вот код для кнопка:

private void button1_Click(object sender, EventArgs e)
{
    if (nomeTextBox.Text.Length == 0)
    {
        MessageBox.Show("Campo nome não pode estar vazio", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    else
    {
        using (UnitsOfWork.UnitOfWork uow = new UnitsOfWork.UnitOfWork())
        {
            Cliente novocliente = new Cliente();
            novocliente.Nome = nomeTextBox.Text;
            novocliente.Endereco = enderecoTextBox.Text;
            novocliente.Data_de_Nascimento = data_de_NascimentoDateTimePicker.Value;
            novocliente.Email = emailTextBox.Text;
            novocliente.Telefone = telefoneTextBox.Text;

            uow.Clientes.Add(novocliente);
            uow.Save();
            uow.Dispose();
        }
    }
}

Мой код UnitsOfWork:

using System;
using ZyonCliente1.Model;

namespace ZyonCliente1.UnitsOfWork
{
    public class UnitOfWork : IUnitOfWork
    {
        private ZyonCliente1.DAL.ContextoBancoDeDados _context;

        public UnitOfWork(ZyonCliente1.DAL.ContextoBancoDeDados context)
        {
            _context = context;
        }

        // Delete this default constructor if using an IoC container
        public UnitOfWork()
        {
            _context = new ZyonCliente1.DAL.ContextoBancoDeDados();
        }

        public Repositories.IClienteRepository Clientes
        {
            get { return new ZyonCliente1.Repositories.ClienteRepository(_context); }
        }

        public void Save()
        {
            _context.SaveChanges();
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_context != null)
                {
                    _context.Dispose();
                    _context = null;
                }
            }
        }
    }
}

И мой DbContext:

namespace ZyonCliente1.DAL
{
    using System;
    using System.Data.Entity;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Diagnostics;
    using ZyonCliente1.Model;
    //Database context file
    public partial class ContextoBancoDeDados : DbContext
    {
        public ContextoBancoDeDados()
            : base("name=ClientesModel")
        {
        }

        public virtual DbSet<Cliente> Clientes { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.Log = (query) => Debug.Write(query);
        }
    }
}

Также не уверен, нужен ли он, но вот мой код класса сущности:

namespace ZyonCliente1.Model
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Data.Entity.Spatial;

    [Table("Clientes")]
    public partial class Cliente
    {
        public int ID { get; set; }

        [Required]
        [StringLength(50)]
        public string Nome { get; set; }

        [StringLength(100)]
        public string Endereco { get; set; }

        public DateTime? Data_de_Nascimento { get; set; }

        [StringLength(80)]
        public string Email { get; set; }

        [StringLength(50)]
        public string Telefone { get; set; }
    }
}

Строки подключения:

<connectionStrings>
    <add name="ClientesModel" connectionString="data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\ClientesDatabase.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"
      providerName="System.Data.SqlClient" />
    <add name="ZyonCliente1.Properties.Settings.ClientesDatabaseConnectionString"
      connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\ClientesDatabase.mdf;Integrated Security=True"
      providerName="System.Data.SqlClient" />
  </connectionStrings>

Я также пытался использовать [Key] в идентификаторе, но он также не работает. Я не уверен, если это необходимо, чтобы поделиться кодом других вещей, таких как репозитории и тому подобное, так как они являются просто обычным шаблоном для UnitOfWork и репозиториев, но я могу включить их здесь или поделиться zip моего проекта для вас ребята. Я действительно в недоумении, что делать здесь, надеюсь, кто-то здесь может мне помочь, пожалуйста? Я уже два дня жарил на это свои мысли.

1 Ответ

1 голос
/ 18 марта 2020

Во-первых, было бы полезно начать с самой простой вещи, прежде чем углубляться в Единицу Работы, Хранилища и т. Д. c. Это только усложняет попытку определить источник проблемы.

Во-первых, если БД настроена для AutoIncrement, вам нужно будет указать EF, что ключ является столбцом идентификации.

[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }

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

При работе с блоками IDisposable и using вам не нужны и явно не следует вызывать Dispose(). using позаботится об этом.

Поэтому я бы предложил начать с простого исходного кода, чтобы убедиться, что вы ищете подходящее место для вещей:

private void button1_Click(object sender, EventArgs e)
{
    if (nomeTextBox.Text.Length == 0)
    {
        MessageBox.Show("Campo nome não pode estar vazio", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }

    using (var context = new ContextoBancoDeDados("ClientesModel"))
    {
        Cliente novocliente = new Cliente
        {
            Nome = nomeTextBox.Text;
            Endereco = nomeTextBox.Text;
            Data_de_Nascimento = data_de_NascimentoDateTimePicker.Value;
            Email = emailTextBox.Text;
            Telefone = telefoneTextBox.Text;
        };  
        context.Clientes.Add(novocliente);
        context.SaveChanges();
    }
}

Если это сработает, затем постепенно вернитесь к своим моделям, а добавьте только то, что действительно оправдано. Это должно иметь причину помимо того, что кто-то говорит, что это «лучшая практика». Такие шаблоны, как Unit of Work и Repository, чрезвычайно полезны, но только в том случае, если они служат цели в вашем коде, например, облегчают модульное тестирование. Если у вас нет таких требований, то они могут просто усложнить ситуацию.

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

...