浏览代码

first commit

moraroxx 1 周之前
当前提交
1ccade9934
共有 18 个文件被更改,包括 1229 次插入0 次删除
  1. 22 0
      .gitignore
  2. 52 0
      App.config
  3. 144 0
      CarApp.csproj
  4. 25 0
      CarApp.sln
  5. 124 0
      Form1.Designer.cs
  6. 229 0
      Form1.cs
  7. 120 0
      Form1.resx
  8. 22 0
      Program.cs
  9. 33 0
      Properties/AssemblyInfo.cs
  10. 71 0
      Properties/Resources.Designer.cs
  11. 117 0
      Properties/Resources.resx
  12. 30 0
      Properties/Settings.Designer.cs
  13. 7 0
      Properties/Settings.settings
  14. 64 0
      README.md
  15. 18 0
      docker-compose.yml
  16. 70 0
      init.sql
  17. 17 0
      packages.config
  18. 64 0
      Руководство_оператора.md

+ 22 - 0
.gitignore

@@ -0,0 +1,22 @@
+# Visual Studio
+.vs/
+bin/
+obj/
+Debug/
+Release/
+*.user
+*.suo
+*.sln.docstates
+
+# Packages
+packages/
+*.nupkg
+
+# User files
+*.user
+*.userosscache
+
+# Build results
+*.dll
+*.exe
+*.pdb

+ 52 - 0
App.config

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <configSections>
+    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+  </configSections>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
+  </startup>
+  <entityFramework>
+    <providers>
+      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+      <provider invariantName="Npgsql" type="Npgsql.NpgsqlServices, EntityFramework6.Npgsql" />
+    </providers>
+    <defaultConnectionFactory type="Npgsql.NpgsqlConnectionFactory, EntityFramework6.Npgsql" />
+  </entityFramework>
+  <system.data>
+    <DbProviderFactories>
+      <remove invariant="Npgsql" />
+      <add name="Npgsql Provider" invariant="Npgsql" description=".NET Framework Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql, Version=4.1.3.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" />
+    </DbProviderFactories>
+  </system.data>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.5.0" newVersion="4.0.5.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Npgsql" publicKeyToken="5d8b90d52f46fda7" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-5.0.18.0" newVersion="5.0.18.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 144 - 0
CarApp.csproj

@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="packages\EntityFramework.6.4.0\build\EntityFramework.props" Condition="Exists('packages\EntityFramework.6.4.0\build\EntityFramework.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{977A0F73-869A-4247-BA9E-67E78FB8E64C}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>CarApp</RootNamespace>
+    <AssemblyName>CarApp</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>packages\EntityFramework.6.4.0\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>packages\EntityFramework.6.4.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework6.Npgsql, Version=6.4.3.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7, processorArchitecture=MSIL">
+      <HintPath>packages\EntityFramework6.Npgsql.6.4.3\lib\net461\EntityFramework6.Npgsql.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
+    </Reference>
+    <Reference Include="Npgsql, Version=5.0.18.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7, processorArchitecture=MSIL">
+      <HintPath>packages\Npgsql.5.0.18\lib\netstandard2.0\Npgsql.dll</HintPath>
+    </Reference>
+    <Reference Include="Npgsql.LegacyPostgis, Version=5.0.18.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7, processorArchitecture=MSIL">
+      <HintPath>packages\Npgsql.LegacyPostgis.5.0.18\lib\netstandard2.0\Npgsql.LegacyPostgis.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Buffers.4.5.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Numerics" />
+    <Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>packages\System.Runtime.CompilerServices.Unsafe.4.6.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Text.Encodings.Web, Version=4.0.4.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Text.Encodings.Web.4.6.0\lib\netstandard2.0\System.Text.Encodings.Web.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Text.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Text.Json.4.6.0\lib\net461\System.Text.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Threading.Channels, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Threading.Channels.4.7.0\lib\netstandard2.0\System.Threading.Channels.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Transactions" />
+    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Form1.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Form1.Designer.cs">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="Form1.resx">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их.  Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('packages\EntityFramework.6.4.0\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', 'packages\EntityFramework.6.4.0\build\EntityFramework.props'))" />
+    <Error Condition="!Exists('packages\EntityFramework.6.4.0\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', 'packages\EntityFramework.6.4.0\build\EntityFramework.targets'))" />
+  </Target>
+  <Import Project="packages\EntityFramework.6.4.0\build\EntityFramework.targets" Condition="Exists('packages\EntityFramework.6.4.0\build\EntityFramework.targets')" />
+</Project>

+ 25 - 0
CarApp.sln

@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35825.156 d17.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CarApp", "CarApp.csproj", "{977A0F73-869A-4247-BA9E-67E78FB8E64C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{977A0F73-869A-4247-BA9E-67E78FB8E64C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{977A0F73-869A-4247-BA9E-67E78FB8E64C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{977A0F73-869A-4247-BA9E-67E78FB8E64C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{977A0F73-869A-4247-BA9E-67E78FB8E64C}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {2FA8AF5D-D8AA-4848-9240-A570F25A1539}
+	EndGlobalSection
+EndGlobal

+ 124 - 0
Form1.Designer.cs

@@ -0,0 +1,124 @@
+namespace CarApp
+{
+    partial class Form1
+    {
+        private System.ComponentModel.IContainer components = null;
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+                components.Dispose();
+            base.Dispose(disposing);
+        }
+
+        private void InitializeComponent()
+        {
+            this.dataGridView1 = new System.Windows.Forms.DataGridView();
+            this.button1 = new System.Windows.Forms.Button();
+            this.button2 = new System.Windows.Forms.Button();
+            this.button3 = new System.Windows.Forms.Button();
+            this.button4 = new System.Windows.Forms.Button();
+            this.button5 = new System.Windows.Forms.Button();
+            this.textBox1 = new System.Windows.Forms.TextBox();
+            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // dataGridView1
+            // 
+            this.dataGridView1.BackgroundColor = System.Drawing.Color.LightBlue;
+            this.dataGridView1.ColumnHeadersHeight = 34;
+            this.dataGridView1.Location = new System.Drawing.Point(12, 60);
+            this.dataGridView1.Name = "dataGridView1";
+            this.dataGridView1.RowHeadersWidth = 62;
+            this.dataGridView1.Size = new System.Drawing.Size(650, 350);
+            this.dataGridView1.TabIndex = 0;
+            // 
+            // button1
+            // 
+            this.button1.BackColor = System.Drawing.Color.LightCyan;
+            this.button1.Location = new System.Drawing.Point(12, 12);
+            this.button1.Name = "button1";
+            this.button1.Size = new System.Drawing.Size(90, 30);
+            this.button1.TabIndex = 5;
+            this.button1.Text = "Загрузить";
+            this.button1.UseVisualStyleBackColor = false;
+            this.button1.Click += new System.EventHandler(this.button1_Click);
+            // 
+            // button2
+            // 
+            this.button2.BackColor = System.Drawing.Color.LightCyan;
+            this.button2.Location = new System.Drawing.Point(110, 12);
+            this.button2.Name = "button2";
+            this.button2.Size = new System.Drawing.Size(90, 30);
+            this.button2.TabIndex = 4;
+            this.button2.Text = "Поиск";
+            this.button2.UseVisualStyleBackColor = false;
+            this.button2.Click += new System.EventHandler(this.button2_Click);
+            // 
+            // button3
+            // 
+            this.button3.BackColor = System.Drawing.Color.LightCyan;
+            this.button3.Location = new System.Drawing.Point(210, 12);
+            this.button3.Name = "button3";
+            this.button3.Size = new System.Drawing.Size(90, 30);
+            this.button3.TabIndex = 3;
+            this.button3.Text = "Экспорт";
+            this.button3.UseVisualStyleBackColor = false;
+            this.button3.Click += new System.EventHandler(this.button3_Click);
+            // 
+            // button4
+            // 
+            this.button4.BackColor = System.Drawing.Color.LightCyan;
+            this.button4.Location = new System.Drawing.Point(310, 12);
+            this.button4.Name = "button4";
+            this.button4.Size = new System.Drawing.Size(90, 30);
+            this.button4.TabIndex = 2;
+            this.button4.Text = "Добавить";
+            this.button4.UseVisualStyleBackColor = false;
+            this.button4.Click += new System.EventHandler(this.button4_Click);
+            // 
+            // button5
+            // 
+            this.button5.BackColor = System.Drawing.Color.LightCyan;
+            this.button5.Location = new System.Drawing.Point(410, 12);
+            this.button5.Name = "button5";
+            this.button5.Size = new System.Drawing.Size(90, 30);
+            this.button5.TabIndex = 1;
+            this.button5.Text = "Удалить";
+            this.button5.UseVisualStyleBackColor = false;
+            this.button5.Click += new System.EventHandler(this.button5_Click);
+            // 
+            // textBox1
+            // 
+            this.textBox1.Location = new System.Drawing.Point(512, 16);
+            this.textBox1.Name = "textBox1";
+            this.textBox1.Size = new System.Drawing.Size(150, 26);
+            this.textBox1.TabIndex = 0;
+            // 
+            // Form1
+            // 
+            this.ClientSize = new System.Drawing.Size(684, 421);
+            this.Controls.Add(this.textBox1);
+            this.Controls.Add(this.button5);
+            this.Controls.Add(this.button4);
+            this.Controls.Add(this.button3);
+            this.Controls.Add(this.button2);
+            this.Controls.Add(this.button1);
+            this.Controls.Add(this.dataGridView1);
+            this.Name = "Form1";
+            this.Text = "Автосалон";
+            ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        private System.Windows.Forms.DataGridView dataGridView1;
+        private System.Windows.Forms.Button button1;
+        private System.Windows.Forms.Button button2;
+        private System.Windows.Forms.Button button3;
+        private System.Windows.Forms.Button button4;
+        private System.Windows.Forms.Button button5;
+        private System.Windows.Forms.TextBox textBox1;
+    }
+}

+ 229 - 0
Form1.cs

@@ -0,0 +1,229 @@
+using System;
+using System.Data;
+using System.Windows.Forms;
+using Npgsql;
+
+namespace CarApp
+{
+    public partial class Form1 : Form
+    {
+        private string connString = "Host=245e1-rw.db.pub.dbaas.postgrespro.ru;Database=dbimport;Username=nikolaeva_sa;Password=$SD$fF7U$z#;SSL Mode=Require;Trust Server Certificate=true;";
+
+        public Form1()
+        {
+            InitializeComponent();
+        }
+
+        private bool IsValidInput(string input)
+        {
+            if (string.IsNullOrWhiteSpace(input))
+                return false;
+
+            string[] forbidden = { "--", ";", "DROP", "DELETE", "INSERT", "UPDATE", "ALTER" };
+            foreach (string f in forbidden)
+            {
+                if (input.ToUpper().Contains(f))
+                    return false;
+            }
+            return true;
+        }
+
+        private void button1_Click(object sender, EventArgs e)
+        {
+            try
+            {
+                using (var cn = new NpgsqlConnection(connString))
+                {
+                    cn.Open();
+                    string sql = "SELECT car_id, brand, model, year, price FROM car";
+                    var da = new NpgsqlDataAdapter(sql, cn);
+                    DataTable dt = new DataTable();
+                    da.Fill(dt);
+                    dataGridView1.DataSource = dt;
+                }
+                MessageBox.Show("Данные загружены!");
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show("Ошибка: " + ex.Message);
+            }
+        }
+
+        private void button2_Click(object sender, EventArgs e)
+        {
+            if (!string.IsNullOrWhiteSpace(textBox1.Text) && !IsValidInput(textBox1.Text))
+            {
+                MessageBox.Show("Некорректный поисковый запрос!", "Ошибка");
+                return;
+            }
+            try
+            {
+                using (var cn = new NpgsqlConnection(connString))
+                {
+                    cn.Open();
+                    string sql = "SELECT car_id, brand, model, year, price FROM car WHERE brand ILIKE @s";
+                    var cmd = new NpgsqlCommand(sql, cn);
+                    cmd.Parameters.AddWithValue("@s", "%" + textBox1.Text + "%");
+                    var da = new NpgsqlDataAdapter(cmd);
+                    DataTable dt = new DataTable();
+                    da.Fill(dt);
+                    dataGridView1.DataSource = dt;
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show("Ошибка: " + ex.Message);
+            }
+        }
+
+        private void button3_Click(object sender, EventArgs e)
+        {
+            SaveFileDialog sfd = new SaveFileDialog();
+            sfd.Filter = "CSV|*.csv";
+            sfd.FileName = "cars.csv";
+
+            if (sfd.ShowDialog() == DialogResult.OK)
+            {
+                using (System.IO.StreamWriter sw = new System.IO.StreamWriter(sfd.FileName))
+                {
+                    for (int i = 0; i < dataGridView1.Columns.Count; i++)
+                        sw.Write(dataGridView1.Columns[i].HeaderText + (i == dataGridView1.Columns.Count - 1 ? "" : ";"));
+                    sw.WriteLine();
+
+                    foreach (DataGridViewRow row in dataGridView1.Rows)
+                    {
+                        if (row.IsNewRow) continue;
+                        for (int i = 0; i < dataGridView1.Columns.Count; i++)
+                            sw.Write(row.Cells[i].Value?.ToString() + (i == dataGridView1.Columns.Count - 1 ? "" : ";"));
+                        sw.WriteLine();
+                    }
+                }
+                MessageBox.Show("Экспорт завершён!");
+            }
+        }
+
+
+        private void button4_Click(object sender, EventArgs e)
+        {
+            // ДИАЛОГ ДОБАВЛЕНИЯ
+            Form addForm = new Form();
+            addForm.Text = "Добавить авто";
+            addForm.Size = new System.Drawing.Size(320, 280);
+            addForm.StartPosition = FormStartPosition.CenterParent;
+
+            TextBox txtReg = new TextBox() { Location = new System.Drawing.Point(120, 20), Size = new System.Drawing.Size(150, 23) };
+            TextBox txtBrand = new TextBox() { Location = new System.Drawing.Point(120, 55), Size = new System.Drawing.Size(150, 23) };
+            TextBox txtModel = new TextBox() { Location = new System.Drawing.Point(120, 90), Size = new System.Drawing.Size(150, 23) };
+            TextBox txtYear = new TextBox() { Location = new System.Drawing.Point(120, 125), Size = new System.Drawing.Size(150, 23) };
+            TextBox txtPrice = new TextBox() { Location = new System.Drawing.Point(120, 160), Size = new System.Drawing.Size(150, 23) };
+
+            addForm.Controls.Add(new Label() { Text = "Рег. номер:", Location = new System.Drawing.Point(20, 23), Size = new System.Drawing.Size(80, 23) });
+            addForm.Controls.Add(txtReg);
+            addForm.Controls.Add(new Label() { Text = "Марка:", Location = new System.Drawing.Point(20, 58), Size = new System.Drawing.Size(80, 23) });
+            addForm.Controls.Add(txtBrand);
+            addForm.Controls.Add(new Label() { Text = "Модель:", Location = new System.Drawing.Point(20, 93), Size = new System.Drawing.Size(80, 23) });
+            addForm.Controls.Add(txtModel);
+            addForm.Controls.Add(new Label() { Text = "Год:", Location = new System.Drawing.Point(20, 128), Size = new System.Drawing.Size(80, 23) });
+            addForm.Controls.Add(txtYear);
+            addForm.Controls.Add(new Label() { Text = "Цена:", Location = new System.Drawing.Point(20, 163), Size = new System.Drawing.Size(80, 23) });
+            addForm.Controls.Add(txtPrice);
+
+            Button btnOk = new Button() { Text = "OK", Location = new System.Drawing.Point(70, 200), Size = new System.Drawing.Size(70, 30), DialogResult = DialogResult.OK };
+            Button btnCancel = new Button() { Text = "Отмена", Location = new System.Drawing.Point(160, 200), Size = new System.Drawing.Size(70, 30), DialogResult = DialogResult.Cancel };
+            addForm.Controls.Add(btnOk);
+            addForm.Controls.Add(btnCancel);
+
+            if (addForm.ShowDialog() == DialogResult.OK)
+            {
+               
+                if (!IsValidInput(txtBrand.Text))
+                {
+                    MessageBox.Show("Некорректный ввод марки!", "Ошибка");
+                    return;
+                }
+                if (!IsValidInput(txtModel.Text))
+                {
+                    MessageBox.Show("Некорректный ввод модели!", "Ошибка");
+                    return;
+                }
+                if (!IsValidInput(txtReg.Text))
+                {
+                    MessageBox.Show("Некорректный ввод регистрационного номера!", "Ошибка");
+                    return;
+                }
+
+                int year;
+                if (!int.TryParse(txtYear.Text, out year) || year < 1900 || year > DateTime.Now.Year + 1)
+                {
+                    MessageBox.Show("Некорректный год!", "Ошибка");
+                    return;
+                }
+
+                decimal price;
+                if (!decimal.TryParse(txtPrice.Text, out price) || price <= 0)
+                {
+                    MessageBox.Show("Некорректная цена!", "Ошибка");
+                    return;
+                }
+               
+
+                try
+                {
+                    using (var cn = new NpgsqlConnection(connString))
+                    {
+                        cn.Open();
+                        string sql = "INSERT INTO car (reg_number, brand, model, year, price) VALUES (@r, @b, @m, @y, @p)";
+                        var cmd = new NpgsqlCommand(sql, cn);
+                        cmd.Parameters.AddWithValue("@r", txtReg.Text);
+                        cmd.Parameters.AddWithValue("@b", txtBrand.Text);
+                        cmd.Parameters.AddWithValue("@m", txtModel.Text);
+                        cmd.Parameters.AddWithValue("@y", year);
+                        cmd.Parameters.AddWithValue("@p", price);
+                        cmd.ExecuteNonQuery();
+                    }
+                    MessageBox.Show("Добавлено!");
+                    button1_Click(null, null);
+                }
+                catch (Exception ex)
+                {
+                    MessageBox.Show("Ошибка: " + ex.Message);
+                }
+            }
+        }
+        // УДАЛИТЬ
+        private void button5_Click(object sender, EventArgs e)
+        {
+            if (dataGridView1.SelectedRows.Count == 0)
+            {
+                MessageBox.Show("Выберите строку для удаления");
+                return;
+            }
+
+            int id = Convert.ToInt32(dataGridView1.SelectedRows[0].Cells["car_id"].Value);
+            string name = dataGridView1.SelectedRows[0].Cells["brand"].Value.ToString();
+
+            DialogResult res = MessageBox.Show($"Удалить {name}?", "Подтверждение", MessageBoxButtons.YesNo);
+
+            if (res == DialogResult.Yes)
+            {
+                try
+                {
+                    using (var cn = new NpgsqlConnection(connString))
+                    {
+                        cn.Open();
+                        string sql = "DELETE FROM car WHERE car_id=@id";
+                        var cmd = new NpgsqlCommand(sql, cn);
+                        cmd.Parameters.AddWithValue("@id", id);
+                        cmd.ExecuteNonQuery();
+                    }
+                    MessageBox.Show("Удалено!");
+                    button1_Click(null, null);
+                }
+                catch (Exception ex)
+                {
+                    MessageBox.Show("Ошибка: " + ex.Message);
+                }
+            }
+        }
+    }
+}

+ 120 - 0
Form1.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 22 - 0
Program.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace CarApp
+{
+    static class Program
+    {
+        /// <summary>
+        /// Главная точка входа для приложения.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new Form1());
+        }
+    }
+}

+ 33 - 0
Properties/AssemblyInfo.cs

@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// Общие сведения об этой сборке предоставляются следующим набором
+// набора атрибутов. Измените значения этих атрибутов для изменения сведений,
+// связанных со сборкой.
+[assembly: AssemblyTitle("CarApp")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HP")]
+[assembly: AssemblyProduct("CarApp")]
+[assembly: AssemblyCopyright("Copyright © HP 2026")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми
+// для компонентов COM. Если необходимо обратиться к типу в этой сборке через
+// COM, следует установить атрибут ComVisible в TRUE для этого типа.
+[assembly: ComVisible(false)]
+
+// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM
+[assembly: Guid("977a0f73-869a-4247-ba9e-67e78fb8e64c")]
+
+// Сведения о версии сборки состоят из указанных ниже четырех значений:
+//
+//      Основной номер версии
+//      Дополнительный номер версии
+//      Номер сборки
+//      Редакция
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 71 - 0
Properties/Resources.Designer.cs

@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     Этот код создан программным средством.
+//     Версия среды выполнения: 4.0.30319.42000
+//
+//     Изменения в этом файле могут привести к неправильному поведению и будут утрачены, если
+//     код создан повторно.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CarApp.Properties
+{
+
+
+    /// <summary>
+    ///   Класс ресурсов со строгим типом для поиска локализованных строк и пр.
+    /// </summary>
+    // Этот класс был автоматически создан при помощи StronglyTypedResourceBuilder
+    // класс с помощью таких средств, как ResGen или Visual Studio.
+    // Для добавления или удаления члена измените файл .ResX, а затем перезапустите ResGen
+    // с параметром /str или заново постройте свой VS-проект.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Возврат кэшированного экземпляра ResourceManager, используемого этим классом.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CarApp.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Переопределяет свойство CurrentUICulture текущего потока для всех
+        ///   подстановки ресурсов с помощью этого класса ресурсов со строгим типом.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 30 - 0
Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CarApp.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 64 - 0
README.md

@@ -0,0 +1,64 @@
+# Руководство оператора программы "Автосалон"
+
+## Аннотация
+
+Руководство по работе с программой учёта автомобилей.
+
+## Введение
+
+### Область применения
+
+Программа предназначена для просмотра и поиска автомобилей.
+
+### Основные возможности
+
+1. Просмотр списка автомобилей
+2. Поиск по марке или модели
+3. Вход с разными правами
+
+## Подготовка к работе
+
+### Установка
+
+1. Установите PostgreSQL
+2. Создайте базу `dbimport`
+3. Выполните `init.sql`
+4. Запустите приложение
+
+### Проверка работоспособности
+
+1. Запустите приложение
+2. Введите `admin` / `Admin123!`
+3. Нажмите "Загрузить"
+4. Появится список автомобилей
+
+## Описание операций
+
+### Форма входа
+
+| Поле | Действие |
+|------|----------|
+| Логин | Введите имя пользователя |
+| Пароль | Введите пароль |
+
+### Главное окно
+
+| Кнопка | Действие |
+|--------|----------|
+| Загрузить | Обновить список |
+| Поиск | Найти по марке |
+
+## Аварийные ситуации
+
+| Ситуация | Решение |
+|----------|---------|
+| Ошибка подключения | Проверьте PostgreSQL |
+| Неверный пароль | Введите правильные данные |
+| Пустая таблица | Загрузите данные в БД |
+
+## Термины и сокращения
+
+| Термин | Описание |
+|--------|----------|
+| БД | База данных |
+| UI | Интерфейс пользователя |

+ 18 - 0
docker-compose.yml

@@ -0,0 +1,18 @@
+version: '3.8'
+
+services:
+  postgres:
+    image: postgres:14
+    container_name: car_db
+    environment:
+      POSTGRES_USER: nikolaeva_sa
+      POSTGRES_PASSWORD: $SD$fF7U$z#
+      POSTGRES_DB: dbimport
+    ports:
+      - "5432:5432"
+    restart: always
+    volumes:
+      - postgres_data:/var/lib/postgresql/data
+
+volumes:
+  postgres_data:

+ 70 - 0
init.sql

@@ -0,0 +1,70 @@
+CREATE TABLE employee (
+    employee_id SERIAL PRIMARY KEY,
+    full_name VARCHAR(150) NOT NULL,
+    position VARCHAR(100) NOT NULL
+);
+
+CREATE TABLE client (
+    client_id SERIAL PRIMARY KEY,
+    full_name VARCHAR(150) NOT NULL,
+    phone VARCHAR(20) NOT NULL,
+    address VARCHAR(200),
+    passport VARCHAR(20) NOT NULL
+);
+
+CREATE TABLE car (
+    car_id SERIAL PRIMARY KEY,
+    reg_number VARCHAR(10) UNIQUE NOT NULL,
+    brand VARCHAR(50) NOT NULL,
+    model VARCHAR(50) NOT NULL,
+    year INT,
+    price NUMERIC(10,2) NOT NULL,
+    status VARCHAR(50) DEFAULT 'в наличии'
+);
+
+CREATE TABLE warehouse (
+    warehouse_id SERIAL PRIMARY KEY,
+    address VARCHAR(200) NOT NULL
+);
+
+CREATE TABLE supplier (
+    supplier_id SERIAL PRIMARY KEY,
+    name VARCHAR(150) NOT NULL,
+    address VARCHAR(200),
+    phone VARCHAR(20)
+);
+
+CREATE TABLE contract (
+    contract_id SERIAL PRIMARY KEY,
+    car_id INT NOT NULL REFERENCES car(car_id),
+    client_id INT NOT NULL REFERENCES client(client_id),
+    employee_id INT NOT NULL REFERENCES employee(employee_id),
+    contract_date DATE NOT NULL DEFAULT CURRENT_DATE,
+    sale_price NUMERIC(10,2) NOT NULL
+);
+
+CREATE TABLE orders (
+    order_id SERIAL PRIMARY KEY,
+    client_id INT NOT NULL REFERENCES client(client_id),
+    car_id INT NOT NULL REFERENCES car(car_id),
+    order_date DATE NOT NULL DEFAULT CURRENT_DATE,
+    status VARCHAR(50) DEFAULT 'новый'
+);
+
+-- Поставки 
+CREATE TABLE supplier_car (
+    supplier_car_id SERIAL PRIMARY KEY,
+    supplier_id INT NOT NULL REFERENCES supplier(supplier_id),
+    car_id INT NOT NULL REFERENCES car(car_id),
+    supply_date DATE NOT NULL DEFAULT CURRENT_DATE,
+    supply_price NUMERIC(10,2) NOT NULL
+);
+
+-- Хранение на складах
+CREATE TABLE car_warehouse (
+    car_warehouse_id SERIAL PRIMARY KEY,
+    car_id INT NOT NULL REFERENCES car(car_id),
+    warehouse_id INT NOT NULL REFERENCES warehouse(warehouse_id),
+    arrival_date DATE NOT NULL DEFAULT CURRENT_DATE,
+    quantity INT DEFAULT 1
+);

+ 17 - 0
packages.config

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="EntityFramework" version="6.4.0" targetFramework="net48" />
+  <package id="EntityFramework6.Npgsql" version="6.4.3" targetFramework="net48" />
+  <package id="Microsoft.Bcl.AsyncInterfaces" version="1.0.0" targetFramework="net48" />
+  <package id="Npgsql" version="5.0.18" targetFramework="net48" />
+  <package id="Npgsql.LegacyPostgis" version="5.0.18" targetFramework="net48" />
+  <package id="System.Buffers" version="4.5.0" targetFramework="net48" />
+  <package id="System.Memory" version="4.5.3" targetFramework="net48" />
+  <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
+  <package id="System.Runtime.CompilerServices.Unsafe" version="4.6.0" targetFramework="net48" />
+  <package id="System.Text.Encodings.Web" version="4.6.0" targetFramework="net48" />
+  <package id="System.Text.Json" version="4.6.0" targetFramework="net48" />
+  <package id="System.Threading.Channels" version="4.7.0" targetFramework="net48" />
+  <package id="System.Threading.Tasks.Extensions" version="4.5.3" targetFramework="net48" />
+  <package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
+</packages>

+ 64 - 0
Руководство_оператора.md

@@ -0,0 +1,64 @@
+# Руководство оператора программы "Автосалон"
+
+## Аннотация
+
+Руководство по работе с программой учёта автомобилей.
+
+## Введение
+
+### Область применения
+
+Программа предназначена для просмотра и поиска автомобилей.
+
+### Основные возможности
+
+1. Просмотр списка автомобилей
+2. Поиск по марке или модели
+3. Вход с разными правами
+
+## Подготовка к работе
+
+### Установка
+
+1. Установите PostgreSQL
+2. Сделать подключение к `dbimport`
+3. Выполните `init.sql`
+4. Запустите приложение
+
+### Проверка работоспособности
+
+1. Запустите приложение
+2. Введите логин и пароль
+3. Нажмите "Загрузить"
+4. Появится список автомобилей
+
+## Описание операций
+
+### Форма входа
+
+| Поле | Действие |
+|------|----------|
+| Логин | Введите имя пользователя |
+| Пароль | Введите пароль |
+
+### Главное окно
+
+| Кнопка | Действие |
+|--------|----------|
+| Загрузить | Обновить список |
+| Поиск | Найти по марке |
+
+## Аварийные ситуации
+
+| Ситуация | Решение |
+|----------|---------|
+| Ошибка подключения | Проверьте PostgreSQL |
+| Неверный пароль | Введите правильные данные |
+| Пустая таблица | Загрузите данные в БД |
+
+## Термины и сокращения
+
+| Термин | Описание |
+|--------|----------|
+| БД | База данных |
+| UI | Интерфейс пользователя |