Base solution for your next web application
Open Closed

sqlite error 19 'foreign key constraint failed #4691


User avatar
0
manojreddy created

I have two entities Entity1 and Entity2. When I'm running test case to create Entity1, It's giving me the below error.

sqlite error 19 'foreign key constraint failed'

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Abp.Domain.Entities.Auditing;
using MyCompany.MyProject.Entity1s;
using MyCompany.MyProject.Business.Model.Entity2s;

namespace MyCompany.MyProject.Business.Model.Entity1s
{
    [Table("Entity1")]
    public class Entity1 : FullAuditedEntity
    {
        [ForeignKey("Entity2Id")]
        public virtual Entity2 Entity2 { get; set; }
        public virtual int Entity2Id { get; set; }
    }
}
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using Abp.Application.Services.Dto;
using MyCompany.MyProject.Business.Dto.Entity1s;
using MyCompany.MyProject.Business.Dto.Entity2s;
using MyCompany.MyProject.Business.Services.Entity1s;
using MyCompany.MyProject.Business.Services.Entity2s;
using MyCompany.MyProject.Tests.AppTestBases;
using Shouldly;
using Xunit;

namespace MyCompany.MyProject.Tests.Entity1s
{
    public class Entity1AppService_Test : Entity1TestBase
    {
        public readonly IEntity2AppService _entity2AppService;
        public readonly IEntity1AppService entity1AppService;
		
        public Entity1AppService_Test()
        {
            entity1AppService = Resolve<IEntity1AppService>();
            _entity2AppService = Resolve<IEntity2AppService>();
        }

        #region Entity1 Tests
        [Fact]
        public async Task Should_Create_Entity1_With_Valid_Arguments()
        {
            var Entity1 = await CreateNewEntity1(K_TESTSKU1);
           Entity1.Id =  await _Entity1AppService.CreateEntity1(Entity1);

            UsingDbContext(context =>
            {
                context.Entity1.FirstOrDefault(
                    u => u.Entity1Name == Entity1.Entity1Name
                ).ShouldNotBeNull();
                context.Entity1PLU.FirstOrDefault(
                    u => u.Entity1Id == Entity1.Id).ShouldNotBeNull();
                context.Entity1Supplier.FirstOrDefault(
                    u => u.Entity1Id == Entity1.Id).ShouldNotBeNull();
            });
        }
		
        #endregion

        #region Private Methods

        private async Task<FetchEntity1> CreateNewEntity1(string sku)
        {
            FetchEntity2 entity2 = await entity2Base.AddEntity2ToDBAsync(entity2Base.CreateEntity2Entity(
                Entity2TestBase.K_TESTENTITYCODE1,
                Entity2TestBase.K_TESTDESC1
                ));

            return await AddEntity1ToDBAsync(CreateEntity1Entity(sku, entity2.Id));
		}
        #endregion
    }
}

namespace MyCompany.MyProject.Tests.AppTestBases
{
    public class Entity2TestBase : AppTestBase
    {
		public async Task<FetchEntity2> AddEntity2ToDBAsync(Entity2Input entity2Dto)
		{
			await _entity2AppService.CreateEntity2(entity2Dto);
			await CleanQueue();

			var entity2s = _entity2AppService.GetSearchEntity2(
				new FetchEntity2Input() { Entity2Code = entity2Dto.Entity2Code, LanguageCode = AppConsts.DefaultLanguageCode }
				);

			return entity2s.Items.First();
		}
	}
}

But When I replace method CreateNewEntity1 with the below method it works fine.

private async Task<Entity1DetailsDto> CreateNewEntity1(string sku)
{
	var entity2 = entity2Base.CreateEntity2Entity(
		Entity2TestBase.K_TESTENTITY2CODE1,
		Entity2TestBase.K_TESTDESC1
		);

	await _entity2AppService.CreateEntity2(entity2);

	var entity2List = _entity2AppService.GetSearchEntity2(new FetchEntity2Input()
	{ 
		Entity2Code = entity2.Entity2Code
	});
	
	return CreateEntity1Entity(sku, entity2List.Items.First().Id);

}

So why is it failing in the first case? Even if I'm passing the inserting the correct value of Entity2Id in the Entity1 table. And why is it working if I 'm calling _entity2AppService.CreateEntity2(entity2) inside Entity1AppService_Test class. Is it related to Context? or this record is deleted for Entity2 when I'm returning from AddEntity2ToDBAsync method?

How can I verify the SQLite table records? Is there any way to check tables once test case is finished or during test case execution?


12 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    The error message is not very clear but I guess the vlaue of "entity2.Id" is not filled when you pass it to CreateEntity1Entity in the failed test.

    Have you debugged it to see entity2.Id's value ?

  • User Avatar
    0
    manojreddy created

    I'm passing the correct value of entity2.Id and I have tried to see in debug mode also.

  • User Avatar
    0
    aaron created
    Support Team

    What's the value of entity2.Id?

  • User Avatar
    0
    manojreddy created

    entity2.Id is 1

  • User Avatar
    0
    aaron created
    Support Team

    Is that set explicitly? Try calling SaveChanges.

  • User Avatar
    0
    manojreddy created

    Why should I set it explicitly?

  • User Avatar
    0
    aaron created
    Support Team

    You should not.

  • User Avatar
    0
    manojreddy created

    yes, that's what I'm saying.

    Why should I set it explicitly? I'm getting it from DB only.

    I'm not stupid

  • User Avatar
    0
    ismcagdas created
    Support Team

    @ManojReddy, I have asked because there is a possibility that value of "entity2.Id" can be 0 if context.SaveChanges() is not called.

    I assumed, in your first scenario, context.SaveChanges() is not called but in the second scenario it is called. Maybe I'm wrong but we are trying to understand the cause of the problem.

    No one is saying that you are stupid, please don't take it wrong.

    Is it possible for you to share a minimal reproduction code for this scenario ? Can we use the code in your initial post ?

  • User Avatar
    0
    manojreddy created

    Yes you can use the code in my initial post.

  • User Avatar
    0
    aaron created
    Support Team

    Each TestBase registers its own in-memory database. Don't call methods of another TestBase.

  • User Avatar
    0
    ismcagdas created
    Support Team

    @ManojReddy, @aaron is right, can you change your code according to @aaron's suggestion ?