Reputation: 327
I have two models that I'd like to specify a one-to-many relationship between, but I can't seem to get it to work. Here are the models:
public class Apple
{
public int Id { get; set; }
public int ThingId { get; set; }
public List<Banana> Bananas { get; set; }
}
public class Banana
{
public int Id { get; set; }
public int ThingId { get; set; }
[ForeignKey("ThingId")]
public Apple Apple { get; set; }
}
As you can see, both class Apple
and class Banana
have a column in them called ThingId
and that's how I'd like to join the associations together. This is a legacy DB so I can't change the column names. However, when I run a query like this, I don't get an array of B
objects back even though I know they exist.
var thing = _context.Apples.Include(a => a.Bananas).FirstOrDefault();
// thing - properly populated but the "Bananas" association is null
Any ideas on how I can get this to work properly using a custom column like this (preferably without fluent syntax since I prefer attributes, but not a big deal if that's necessary).
Thanks!
Edit: The link in the answer below by Rafi did the trick. Here's what I ending up using via the Fluent API.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Banana>()
.HasOne(b => b.Apple)
.WithMany(a => a.Bananas)
.HasForeignKey(a => a.ThingId)
.HasPrincipalKey(b => b.ThingId);
}
Upvotes: 0
Views: 959
Reputation: 4267
Given your scenario, we're going to have to set some few Constraints in order to get the relationship to work. In this case, each apple has a unique key
called Id
, which would be a feasible property to use as foreign key to Apple
related entities. But SQL does allow other columns to be used as foreign keys provided that they are unique for each row, which is Apple
in your case.
So to achieve this let's look at your given code:
public class Apple
{
public int Id { get; set; }
public int ThingId { get; set; }
public List<Banana> Bananas { get; set; }
}
public class Banana
{
public int Id { get; set; }
public int ThingId { get; set; }
public Apple Apple { get; set; }
}
From your code, we'll have to make ThingId
uniquer for every Apple
. So let's configure that with Fluent API:
modelBuilder.Entity<Apple>()
.HasIndex(ux=>ux.ThingId)
.IsUnique()
.Isclustered(false);
Then, with continue to configure the one-to-many relationship with fluend API:
modelBuilder.Entity<Apple>()
.HasMany(apple => apple.Bananas)
.WithOne(banana => banana.Apple)
.HasForeignKey(banana => banana.ThingId)
.Isrequired(false)
.OnDelete(DeleteBehavior.Cascade); // You can set the DeleteBehavior here
An then your relationship will be set correctly.
Conclusion
Let's recap, A ForeignKey
has to be a unique key from the foreign entity. I always recommend you to use FluentAPI for configuring your relationships, because you have control over many attributes of that relationship.
Upvotes: 1
Reputation: 6424
Try modifying your data models as in the following example:
public class Apple
{
public int Id { get; set; }
public List<Banana> Bananas { get; set; }
}
public class Banana
{
public int Id { get; set; }
[ForeignKey("Apple")]
public int AppleId { get; set; }
public Apple Apple { get; set; }
}
Update:
If ThingId
is not a primary key consider using GroupJoin
as below:
_context.Apples.GroupJoin(
bana_context.Bananas,
apple => apple.ThingId,
banana => banana.ThingId,
(apple, bananas) =>
{
apple.bananas = bananas.ToList();
return apple;
}
)
Upvotes: 2