'EF Core One to Many with GenericId
I am trying to link one model to multiple other modells via a GenricId. All my id fields are Guid's and not int's.
Here ist the example models:
public class BaseEntity
{
public Guid Id { get; set; }
public string TenantId { get; set; }
public DateTime? CreatedAt { get; set; }
public Guid? CreatedBy { get; set; }
public DateTime? ModifiedAt { get; set; }
public Guid? ModifiedBy { get; set; }
public bool Deleted { get; set; } = false;
}
public class Contact : BaseEntity
{
[StringLength(150)]
[Required]
public string CompanyName { get; set; } = String.Empty;
public ContactType ContactType { get; set; }
[StringLength(100)]
[Required]
public string Email { get; set; } = String.Empty;
[StringLength(30)]
[Required]
public string Telefon1 { get; set; } = String.Empty;
[StringLength(30)]
[Required]
public string Telefon2 { get; set; } = String.Empty;
[StringLength(30)]
[Required]
public string Fax { get; set; } = String.Empty;
public Guid PersonId { get; set; }
public Person? Person { get; set; }
// How do I tell the relation to use the genericId field on Address model for the relationship?
public IList<Address> Addresses { get; set; } = new List<Address>();
[NotMapped]
public IList<Guid>? AddressIds { get; set; }
}
public class Address : BaseEntity
{
public Guid GenericId { get; set; }
public AddressType AddressType { get; set; } = AddressType.Private;
public bool CurrentResidence { get; set; } = true;
[StringLength(200)]
[Required]
public string Street { get; set; } = String.Empty;
[StringLength(20)]
[Required]
public string PostalCode { get; set; } = String.Empty;
[StringLength(100)]
[Required]
public string City { get; set; } = String.Empty;
}
How can I tell the ContactModel that the ForeignKey on the Remote Object (Address) is not ContactId but rather GenericId. Also I have other models which should also link to the address via the GenericId on Address Model? Preferably using annotations and NOT fluent API :)
Solution 1:[1]
As your relationship between Contact and Address is a One-to-Many, this is the Address which will hold the foreign key of the contact.
Did you try adding an Alternate Key Property ? https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=data-annotations%2Cdata-annotations-simple-key%2Csimple-key#principal-key
It seems that you cannot create an alternate key without using the Fluent API. Does annotations are absolutely required ?
Personally, I prefer using Fluent API. I like to have my models not linked to an implementation of how those models references each other. And you will probably have a DbContext anyway. But this is my opinion.
In your case, your DbContext should be
public class MyContext : DbContext
{
public DbSet<Contact> Contacts{ get; set; }
public DbSet<Address> Addresses{ get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Address>()
.HasOne(s => s.Contact)
.WithMany(c => c.Addresses)
.HasForeignKey(s => s.ContactGenericId)
.HasPrincipalKey(c => c.GenericId);
}
}
public class Contact : BaseEntity
{
//..previous stuff
public Guid GenericId {get; set;}
public IList<Address> Addresses { get; set; } = new List<Address>();
//..not required !
//[NotMapped]
//public IList<Guid>? AddressIds { get; set; }
}
public class Address : BaseEntity
{
//not required
//public Guid GenericId { get; set; }
//...previous stuff
public Contact Contact {get; set;}
public Guid ContactGenericId {get; set;}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | dedieuma |

