question

PrathameshShende avatar image
0 Votes"
PrathameshShende asked ZhiLv-MSFT commented

Inverse Property in EF Core

How to apply Inverse Property in Ef Core I gone through so many examples but didnt helps me. So

my models like this
public class Customer
{

     public string Name { get; set; }
     public int AddedByID { get; set; }
     public int EditedByID { get; set; }
     public int DeletedByID { get; set; }
     [InverseProperty("Customers")]
     [ForeignKey("AddedByID")]
     public virtual UserLogin AddedBy { get; set; }
     [ForeignKey("EditedByID")]
     public virtual UserLogin EditedBy { get; set; }
     [ForeignKey("DeletedByID")]
     public virtual UserLogin DeletedBy { get; set; }

}
public class Vendor
{

     public string Name { get; set; }
     public int AddedByID { get; set; }
     public int EditedByID { get; set; }
     public int DeletedByID { get; set; }
     [InverseProperty("Vendors")]
     [ForeignKey("AddedByID")]
     public virtual UserLogin AddedBy { get; set; }
     [ForeignKey("EditedByID")]
     public virtual UserLogin EditedBy { get; set; }
     [ForeignKey("DeletedByID")]
     public virtual UserLogin DeletedBy { get; set; }

}
public class UserLogin
{
public UserLogin()
{
Customers = new HashSet<Customer>();
Vendors = new HashSet<Vendor>();

     }

public virtual ICollection<Customer> Customers { get; set; }
public virtual ICollection<Vendor> Vendors { get; set; }
}

this only works if I use only model (Customer) if Add this same properties into vendor then it throw error - Unable to determine the relationship represented by navigation 'Custom.Edited By' of type 'UserLogin'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.'

this error is not show if I dont use vendor model

so How do I apply inverse property here

dotnet-aspnet-core-mvc
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

ZhiLv-MSFT avatar image
0 Votes"
ZhiLv-MSFT answered ZhiLv-MSFT commented

Hi @PrathameshShende,

You can set the foreign key to nullable and use InverseProperty as below:

 public class Customer
 {
     [Key]
     public int ID { get; set; }
     public string Name { get; set; }
     [ForeignKey("AddedBy")]
     public int? AddedByID { get; set; }
     [ForeignKey("EditedBy")]
     public int? EditedByID { get; set; }
     [ForeignKey("DeletedBy")]
     public int? DeletedByID { get; set; } 
     public UserLogin AddedBy { get; set; } 
     public UserLogin EditedBy { get; set; } 
     public UserLogin DeletedBy { get; set; }
 }
 public class Vendor
 {
     [Key]
     public int ID { get; set; }
     public string Name { get; set; }
     [ForeignKey("AddedBy")]
     public int? AddedByID { get; set; }
     [ForeignKey("EditedBy")]
     public int? EditedByID { get; set; }
     [ForeignKey("DeletedBy")]
     public int? DeletedByID { get; set; } 
     public UserLogin AddedBy { get; set; }
     public UserLogin EditedBy { get; set; }
     public UserLogin DeletedBy { get; set; }
 }
 public class UserLogin
 { 
     public UserLogin()
     {
         CustomersAdded = new List<Customer>();
         VendorsAdded = new List<Vendor>();
     }

     [Key]
     public int Id { get; set; }
     public string Name { get; set; }

     [InverseProperty("AddedBy")]
     public List<Customer> CustomersAdded { get; set; }
     [InverseProperty("EditedBy")]
     public List<Customer> CustomersEdited { get; set; }
     [InverseProperty("DeletedBy")]
     public List<Customer> CustomersDeleted { get; set; }
     [InverseProperty("AddedBy")]
     public List<Vendor> VendorsAdded { get; set; }
     [InverseProperty("EditedBy")]
     public List<Vendor> VendorsEdited { get; set; }
     [InverseProperty("DeletedBy")]
     public List<Vendor> VendorsDeleted { get; set; }
 }

And configure the cascading delete as NoAction:

 public class ApplicationDbContext : IdentityDbContext
 {
     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
         : base(options)
     {
     }  

     public DbSet<UserLogin> UserLogin { get; set; }
     public DbSet<Customer> Customers { get; set; }
     public DbSet<Vendor> Vendors { get; set; }

     protected override void OnModelCreating(ModelBuilder modelBuilder)
     {
         base.OnModelCreating(modelBuilder);
         modelBuilder.Entity<Customer>()
             .HasOne(c => c.AddedBy)
             .WithMany(c=>c.CustomersAdded)
             .OnDelete(DeleteBehavior.NoAction);
         modelBuilder.Entity<Customer>()
             .HasOne(c => c.EditedBy)
            .WithMany(c => c.CustomersEdited)
             .OnDelete(DeleteBehavior.NoAction);
         modelBuilder.Entity<Customer>()
             .HasOne(c => c.DeletedBy)
            .WithMany(c => c.CustomersDeleted)
             .OnDelete(DeleteBehavior.NoAction);
         modelBuilder.Entity<Vendor>()
             .HasOne(c => c.AddedBy)
            .WithMany(c => c.VendorsAdded)
             .OnDelete(DeleteBehavior.NoAction);
         modelBuilder.Entity<Vendor>()
             .HasOne(c => c.EditedBy)
             .WithMany(c=>c.VendorsEdited)
             .OnDelete(DeleteBehavior.NoAction);
         modelBuilder.Entity<Vendor>()
             .HasOne(c => c.DeletedBy)
             .WithMany(c=>c.VendorsDeleted)
             .OnDelete(DeleteBehavior.NoAction); 
     }
 }

The generated table as below:

143324-image.png

Then, you can add/remove the entity via the ApplicationDbContext, like this:

         _context.UserLogin.Add(new UserLogin()
         {
            Name="AA",
            CustomersAdded= new List<Customer>()
            {
                new Customer(){ Name="Tom"}
            },
             CustomersEdited = new List<Customer>()
            {
                new Customer(){ Name="John"}
            },
             VendorsAdded = new List<Vendor>()
             {
                 new Vendor(){ Name="Jack"}
             }
         });
         _context.SaveChanges();


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Best regards,
Dillion


image.png (46.0 KiB)
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

got it sir. But why did you use set as null property int of AddedByID, EditedByID, DeletedByID

0 Votes 0 ·

Hi @PrathameshShende,

If you don't want to set as the null property for the foreign key, you could add the required attribute, like this:

     [Required]
     [ForeignKey("AddedBy")]
     public int? AddedByID { get; set; }
     [Required]
     [ForeignKey("EditedBy")]
     public int? EditedByID { get; set; }
     [Required]
     [ForeignKey("DeletedBy")]
     public int? DeletedByID { get; set; } 

Then, after migration, the result as below:

146340-image.png

Best regards,
Dillion

0 Votes 0 ·
image.png (11.3 KiB)