Reputation: 901
I have created three different classes and one base class which store different types of addresses. Base class is postal address which has relation to User (to whom is current address attached) and Post, which contain information about zip code and city.
public class PostalAddress
{
public virtual User User { get; set; }
public DateTime LastUsed { get; private set; }
public string OrientationNumber { get; set; }
public int UserId { get; set; }
public int PostId { get; set; }
public int Id { get; set; }
public virtual Post Post { get; private set; }
public string Street { get; set; }
}
public class Post
{
public Post()
{
InvoicingAddresses = new List<InvoicingAddress>();
ShippingAddresses = new List<ShippingAddress>();
UserAddresses = new List<UserAddress>();
}
public virtual City City { get; set; }
public virtual ICollection<InvoicingAddress> InvoicingAddresses { get; private set; }
public virtual ICollection<ShippingAddress> ShippingAddresses { get; private set; }
public virtual ICollection<UserAddress> UserAddresses { get; private set; }
public int CityId { get; set; }
public int Id { get; set; }
public string ZipCode { get; set; }
}
Class PostalAddress is mapped using class PostalAddressMap
public class PostalAddressMap : EntityTypeConfiguration<PostalAddress>
{
public PostalAddressMap()
{
// Primary Key
HasKey(t => t.Id);
// Properties
// Table & Column Mappings
ToTable("PostalAddress");
Property(t => t.Id).HasColumnName("Id");
Property(t => t.LastUsed).HasColumnName("LastUsed").HasColumnType("datetime2");
Property(t => t.OrientationNumber).HasColumnName("OrientationNumber");
Property(t => t.UserId).HasColumnName("UserId");
Property(t => t.PostId).HasColumnName("PostId");
Property(t => t.Street).HasColumnName("Street");
// Relationships
HasRequired(t => t.Post).WithMany(t => t.InvoicingAddresses).HasForeignKey(d => d.PostId);
HasRequired(t => t.User)
.WithMany(t => t.UserAddressess)
.HasForeignKey(d => d.UserId);
}
}
Classes InvoicingAddress, ShippingAddress and UserAddress are inherited from PostalAddress class using Table per hierarchy approach. If I want to set relationships using line
HasRequired(t => t.Post).WithMany(t => t.InvoicingAddresses).HasForeignKey(d => d.PostId);
I receive compiler error Cannot implicitly convert type 'System.Collections.Generic.ICollection<InvoicingAddress>' to 'System.Collections.Generic.ICollection<PostalAddress>'. An explicit conversion exists (are you missing a cast?)
Please, can you help me how can I set foreign key between PostalAddress child classes and other TPT types?
Thank you for any helpful answer.
Upvotes: 0
Views: 734
Reputation: 177163
You must either move the PostId
and Post
properties from the base class PostalAddress
to the derived classes InvoicingAddress
, etc...
public class InvoicingAddress : PostalAddress
{
//...
public int PostId { get; set; }
public virtual Post Post { get; private set; }
}
...and then use a mapping for the derived classes:
public class InvoicingAddressMap : EntityTypeConfiguration<InvoicingAddress>
{
public InvoicingAddressMap()
{
HasRequired(t => t.Post)
.WithMany(t => t.InvoicingAddresses)
.HasForeignKey(d => d.PostId);
}
}
Or you must use a single collection in Post
for the base class:
public virtual ICollection<PostalAddress> Addresses { get; private set; }
Then you can use your original mapping.
The downside of the latter approach is that when you use eager or lazy loading all PostalAddress
es will be loaded and you can't control which type of address you want to load. After the addresses have been loaded you could filter by type in memory though:
var invoicingAddresses = post.Addresses.OfType<InvoicingAddress>();
With explicit loading you can filter too:
var post = context.Posts.Single(p => p.Id == 1);
context.Entry(post).Collection(p => p.Addresses).Query()
.OfType<InvoicingAddress>().Load();
...which would populate the Addresses
collection with the InvoicingAddress
es only.
Upvotes: 1