Search code examples
entity-framework-coreef-code-firstrepository-patternunit-of-workef-fluent-api

EFCore Generic Repository and UnitOfWork Design Pattern


when im trying to create new data and save it, im getting error at the

public int Complete()
       {
           return _context.SaveChanges();
       }

and error is saying me that: The value of 'Agency.ID' is unknown when attempting to save changes. This is because the property is also part of a foreign key for which the principal entity in the relationship is not known. .

i have a Base class like that:

 public class Base
    {
        protected Base()
        {
            CreatedDate = DateTime.Now;
            IsDeleted = false;
            ModifiedDate = null;
        }

        public int ID { get; set; }
        public int? CreatedUserId { get; set; }
        public int? ModifiedUserId { get; set; }
        public string CreatedUserType { get; set; }
        public string ModifiedUserType { get; set; }
        public DateTime? CreatedDate { get; set; }
        public DateTime? ModifiedDate { get; set; }
        public bool? IsActive { get; set; }
        public bool? IsDeleted { get; set; }
    }

i have a Agency class like that :

   public class Agency : Base
    {
        public Agency()
        {
            AgencyIsComplated = false;
        }
        [Required, StringLength(255)]
        public string AgencyName { get; set; }

        [Required, StringLength(255)]
        public string AgencyPhoto { get; set; }

        [Required, StringLength(255)]
        public string AgencyEMail { get; set; }

        [Required, StringLength(13)]
        public string AgencyPhone { get; set; }

        [StringLength(13)]
        public string AgencyBPhone { get; set; }

        [StringLength(255)]
        public string AgencyInfo { get; set; }

        [Required, StringLength(255)]
        public string AgencyTitle { get; set; }

        [Required, StringLength(255)]
        public string AgencyLink { get; set; }

        public int AgencyExportArea { get; set; } // Join table ile yapılacak,ayrı bir tabloda tutulacak

        [Required, StringLength(255)]
        public string AgencyInstagram { get; set; }

        public string AgencyTwitter { get; set; }

        public string AgencyFacebook { get; set; }

        public string AgencyLinkedin { get; set; }

        public string AgencyYoutube { get; set; }

        public bool AgencyIsComplated { get; set; }

        [ForeignKey("CompanyID")]
        public Company Company { get; set; }
        [ForeignKey("LogID")]
        public Log Log { get; set; }
        public virtual ICollection<AgencyCompany> AgencyCompanies { get; set; }
        
        public virtual ICollection<User> Users { get; set; }

        public virtual ICollection<Log> Logs { get; set; }
    }

    public class AgencyConfiguration : IEntityTypeConfiguration<Agency>
    {
        public void Configure(EntityTypeBuilder<Agency> builder)
        {
            builder.HasKey(agency => agency.ID);

            builder.HasMany(a => a.Logs)
                .WithOne(a => a.Agency)
                .HasForeignKey(a=>a.ID)
                .OnDelete(DeleteBehavior.Restrict);

            builder.HasMany(us => us.Users)
                .WithOne(us => us.Agency)
                .HasForeignKey(au=>au.ID)
                .OnDelete(DeleteBehavior.Restrict);

            builder.HasMany(ac => ac.AgencyCompanies)
                .WithOne(ac => ac.Agency)
                .OnDelete(DeleteBehavior.Restrict);
        }
    }

and i have got a UnitOfWork like that:

public class UnitOfWork : IUnitOfWork
    {
        private TradeTurkDBContext _context;
        public UnitOfWork(TradeTurkDBContext context)
        {
            _context = context;
            RepositoryAgency = new RepositoryAgency(_context);
        }
        public IRepository Repository { get; private set; }
        public IRepositoryAgency RepositoryAgency { get; private set; }
        public int Complete()
        {
            return _context.SaveChanges();
        }
        public void Dispose()
        {
            _context.Dispose();
        }
    }

im inheriting that ID on my Base Model. the problem is getting solved when im not defining ID in the base model but i allready set up my mapping on it.

so how can i solve that error without using AgencyID in the Agency model ?


Solution

  • The foreign key is in the details (or child) table. Therefore, e.g. a user, should have an AgencyId as foreign key.

    builder.Entity<User>()
        .HasOne(u => u.Agency)
        .WithMany(a => a.Users)
        .HasForeignKey(u => u.AgencyId)
        .OnDelete(DeleteBehavior.Restrict);
    

    This key automatically points to the primary key of the master (or parent) table.

    User.ID is a primary key. User.AgencyId is a foreign key which (automatically) relates to the primary key Agency.ID.

    E.g. see: Configure One-to-Many Relationships using Fluent API in Entity Framework Core