Как проверить, существует ли запись с определенным идентификатором в БД, чтобы избежать ошибки «Нарушение ограничения PRIMARY KEY» в опубликованном приложении ASP.NET Core MVC? - PullRequest
0 голосов
/ 11 июня 2019

Итак, я уже некоторое время создаю небольшое приложение для интернет-магазина ASP.NET Core, и необходимой его частью было отключение автоматической генерации идентификаторов в некоторых таблицах. Когда я хочу добавить некоторые товары в свою корзину, приложение генерирует исключение SqlException: Violation of PRIMARY KEY constraint 'PK_Tip'. Cannot insert duplicate key in object 'dbo.Tip'. The duplicate key value is (1). The statement has been terminated..

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

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

BestDeal.Models.Korpa.DodajUKorpu (Артикал артикал, int kolicina) в Korpa.cs

        else
        {
            elementKorpe.KolicinaArtikla++;
        }
        try
        {
            **_context.SaveChanges();**
        }
        finally
        {
            _context.Database.CloseConnection();
        }
    }

BestDeal.Controllers.KorpaAppController.DodajKorpa (int artikalID) в KorpaAppController.cs

       // WriteErrorLog(artikalID.ToString());
        Artikal odabrani = _artikliApp.artikliApp.FirstOrDefault(p => p.IdArtikla == artikalID);
        if (odabrani != null)
        {
            _korpica.DodajUKorpu(odabrani, 1);
        }
        **return RedirectToAction("Index");**
    }

TipKreator.cs

public class TipKreator:ITipovi
    {
        List<Tip> listaTipova = new List<Tip>{new Tip { Ime = "Laptopi", idTipa = 1 },
                    new Tip { Ime = "Mobiteli", idTipa = 2 },
                    new Tip { Ime = "Računari", idTipa = 3 },
                    new Tip { Ime = "Računarska oprema", idTipa = 4 } };
        public IEnumerable<Tip> tipoviApp
        {

            get {
                return listaTipova;
            }
        }
        public Tip vratiTip(string nazivTipa)
        {
            foreach (Tip t in listaTipova) if (t.Ime.Equals(nazivTipa)) return t;
            return null; //FLAG
        }
    }

Korpa.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;

namespace BestDeal.Models
{
    //Hajmo reci da je samo lista artikala i njihovih kolicina za pocetak
    //TODO: Integracija ocjena i svega
    public class Korpa
    {
        private readonly BestDealContext _context;

        //List<Tuple<Artikal, Recenzija, double>> podaciOArtiklima;
        [Required]
       List<KorpaInfo> artikliKolicina;
        string idKorpe;
        public Korpa()
        {
        }

        public Korpa(BestDealContext context)
        {
            _context = context;
        }

        public Korpa(string idKorpe, List<KorpaInfo> artikliKolicina)
        {
            IdKorpe = idKorpe;
            ArtikliKolicina = artikliKolicina;
        }

        public static Korpa DajKorpu(IServiceProvider services)
        {
            ISession session = services.GetRequiredService<IHttpContextAccessor>()?
                .HttpContext.Session;

            var context = services.GetService<BestDealContext>();
            string cartId = session.GetString("idKorpe") ?? Guid.NewGuid().ToString();

            session.SetString("idKorpe", cartId);

            return new Korpa(context) { idKorpe = cartId };
        }

        public void DodajUKorpu(Artikal artikal, int kolicina)
        {
            var elementKorpe =
                    _context.KorpaInfo.SingleOrDefault(
                        s => s.A.IdArtikla == artikal.IdArtikla && s.IdKorpe1 == idKorpe);

            if (elementKorpe == null)
            {
                elementKorpe = new KorpaInfo
                {
                    IdKorpe1 = idKorpe,
                    A = artikal,
                KolicinaArtikla = 1
            };

            _context.KorpaInfo.Add(elementKorpe);
            }
            else
            {
                elementKorpe.KolicinaArtikla++;
            }
            try
            {
                _context.SaveChanges();
            }
            finally
            {
                _context.Database.CloseConnection();
            }
        }

        public int IzbaciIzKorpe(Artikal artikal)
        {
            var elementKorpe =
                    _context.KorpaInfo.SingleOrDefault(
                        s => s.A.IdArtikla == artikal.IdArtikla && s.IdKorpe1 == IdKorpe);

            var localAmount = 0;

            if (elementKorpe != null)
            {
                if (elementKorpe.KolicinaArtikla > 1)
                {
                    elementKorpe.KolicinaArtikla--;
                    localAmount = elementKorpe.KolicinaArtikla;
                }
                else
                {
                    _context.KorpaInfo.Remove(elementKorpe);
                }
            }

            _context.SaveChanges();

            return localAmount;
        }

        public List<KorpaInfo> DajNaruceneArtikle()
        {
            return artikliKolicina ??
                   (ArtikliKolicina =
                       _context.KorpaInfo.Where(c => c.IdKorpe1 == idKorpe)
                           .Include(s => s.A)
                           .ToList());
        }

        public void ClearCart()
        {
            var cartItems = _context
                .KorpaInfo
                .Where(cart => cart.IdKorpe1 == idKorpe);

            _context.KorpaInfo.RemoveRange(cartItems);

            _context.SaveChanges();
        }

        public decimal DajUkupnuCijenu()
        {
            var total = _context.KorpaInfo.Where(c => c.IdKorpe1 == idKorpe)
                .Select(c => c.A.CijenaArtikla * c.KolicinaArtikla).Sum();
            return (decimal)total;
        }

        //public List<Tuple<Artikal, Recenzija, double>> PodaciOArtiklima { get => podaciOArtiklima; set => podaciOArtiklima = value; }

        [Key]
        public string IdKorpe { get => idKorpe; set => idKorpe = value; }
        public List<KorpaInfo> ArtikliKolicina { get => artikliKolicina; set => artikliKolicina = value; }

        public void DodajArtikla(Artikal artikal, int kolicina)
        {
            ArtikliKolicina.Add(new KorpaInfo(artikal, kolicina));
        }
    }
}

KorpaAppController.cs

using BestDeal.AdapteriPodataka;
using BestDeal.Models;
using BestDeal.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;

namespace BestDeal.Controllers
{
    public class KorpaAppController : Controller
    {
        private readonly IArtikli _artikliApp;
        private readonly Korpa _korpica;

        public KorpaAppController(IArtikli ak, Korpa k)
        {
            _artikliApp = ak;
            _korpica = k;
        }


        public ViewResult Index()
        {
            var items = _korpica.DajNaruceneArtikle();
            _korpica.ArtikliKolicina = items;

            var korpaPogled = new KorpaViewModel
            {
                korpa = _korpica,
                UkupnaCijena = _korpica.DajUkupnuCijenu()
            };
            return View(korpaPogled);
        }

      /*  public static void WriteErrorLog(string strErrorText)
       {
           try
           {
               //DECLARE THE FILENAME FROM THE ERROR LOG
               string strFileName = "errorLog.txt";
               string strPath = "C:\\Users\\Mirza\\Documents\\GitHub\\Grupa5-TripleDouble";
               //WRITE THE ERROR TEXT AND THE CURRENT DATE-TIME TO THE ERROR FILE
               System.IO.File.AppendAllText(strPath + "\\" + strFileName, strErrorText + " - " + DateTime.Now.ToString() + "\r\n");
           }
           catch (Exception ex)
           {
               WriteErrorLog("Error in WriteErrorLog: " + ex.Message);
           }
       }*/

        public RedirectToActionResult DodajKorpa(int artikalID)
        {
           // WriteErrorLog(artikalID.ToString());
            Artikal odabrani = _artikliApp.artikliApp.FirstOrDefault(p => p.IdArtikla == artikalID);
            if (odabrani != null)
            {
                _korpica.DodajUKorpu(odabrani, 1);
            }
            return RedirectToAction("Index");
        }

        public RedirectToActionResult BrisiKorpa(int artikalID)
        {
            var odabrani = _artikliApp.artikliApp.FirstOrDefault(p => p.IdArtikla == artikalID);
            if (odabrani != null)
            {
                _korpica.IzbaciIzKorpe(odabrani);
            }
            return RedirectToAction("Index");
        }

    }
}

Tip.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace BestDeal.Models
{
    //klasa koja omogucava dodavanje tipova
    public class Tip
    {
        public Tip()
        {
        }
        //TODO:Moguce opcije nekog IDa ili liste specificnih polja koju ima svaki tip (radi razlicitih detalja kod recenzija i sl.)
        public Tip(string ime)
        {
            Ime = ime;
        }

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int idTipa { get; set; }
        public string Ime { get;  set; }
        public override bool Equals(object obj)
        {
            var other = obj as Tip;
            if (other == null)
            {
                return false;
            }
            return other == this;
        }

        public override int GetHashCode()
        {
            return HashCode.Combine(idTipa);
        }

        public static bool operator ==(Tip Tip1, Tip Tip2)
        {
            if (Object.ReferenceEquals(Tip1, null) && Object.ReferenceEquals(Tip2, null))
                return true;

            if (Object.ReferenceEquals(Tip1, null) || Object.ReferenceEquals(Tip2, null))
                return false;

            return Tip1.Ime == Tip2.Ime;
        }
        public static bool operator !=(Tip Tip1, Tip Tip2)
        {
            return !(Tip1 == Tip2);
        }
    }
}

KorpaInfo.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace BestDeal.Models
{
    public class KorpaInfo:Korpa
    {
        string idKorpe;
        Artikal a;
        int kolicinaArtikla;
        int idKomponente;
        public KorpaInfo()
        {
        }

        public KorpaInfo(Artikal a, int kolicinaArtikla)
        {
            this.A = a;
            this.KolicinaArtikla = kolicinaArtikla;
        }

        public KorpaInfo(string idKorpe, Artikal a, int kolicinaArtikla)
        {
            this.idKorpe = idKorpe;
            this.a = a;
            this.kolicinaArtikla = kolicinaArtikla;
        }

        public Artikal A { get => a; set => a = value; }
        public int KolicinaArtikla { get => kolicinaArtikla; set => kolicinaArtikla = value; }

        public string IdKorpe1 { get => idKorpe; set => idKorpe = value; }
    }
}

Я ожидаю, что приложение не аварийно завершит работу после сохранения изменений в БД.

1 Ответ

1 голос
/ 11 июня 2019

Лучшее решение для меня - использовать метод: DbContext.Attach(object), который попытается загрузить связанный объект на основе его первичного ключа.

Если объект отслеживается или существует, метод повторно запустит этот объект.

Если нет, он начнет отслеживать сущность.

Вы также можете выполнить поиск с помощью FirstOrDefault, где вы сможете узнать, существуют ли какие-либо объекты с таким же первичным ключом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...