Reputation: 539
I'm trying to make a database where one of the tables has a one to one relationship and a many to many relationship ... The database created seems to be working as one to one relationship only. here's my model:
public class Trip
{
public int ID { get; set; }
public virtual ICollection<Place> PassingBy { get; set; }
public Place Origin { get; set; }
public Place Destination { get; set; }
public DateTime Time { get; set; }
public int EmptySlots { get; set; }
public virtual ICollection<Person> Attendants { get; set; }
public string AccessKey { get; set; }
}
public class Person
{
public int ID { get; set; }
public string Username { get; set; }
public virtual ICollection<Trip> Trips { get; set; }
}
public class Place
{
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<Trip> Trips { get; set; }
}
public class GARDB : DbContext
{
public DbSet<Trip> Trips { get; set; }
public DbSet<Person> Persons { get; set; }
public DbSet<Place> Places { get; set; }
}
Now, when I do add-migrations and update database. The database has a table called "PersonTrip" which is needed for the many to many relationship. But there is no table for "PlaceTrip" . After some trial and error. I found out it's because of these lines:
public Place Origin { get; set; }
public Place Destination { get; set; }
They cause the relation to be one to many. Non many to many as I want to to be. Is there a way to make the Place-Trip relation like the Person-Trip one but without removing those 2 lines.
Thanks!
EDIT: The Solution
I didn't make clear what I wanted. I wanted to make the line
public virtual ICollection<Place> PassingBy { get; set; }
to be mapped to the line
public virtual ICollection<Trip> Trips { get; set; }
in the Place class. The solution I got to from the answers was this:
replace :
public virtual ICollection<Place> PassingBy { get; set; }
with:
[InverseProperty("Trips")]
public virtual ICollection<Place> PassingBy { get; set; }
and replace :
public virtual ICollection<Trip> Trips { get; set; }
in the Place class with:
[InverseProperty("PassingBy")]
public virtual ICollection<Trip> Trips { get; set; }
and add this include at the top:
using System.ComponentModel.DataAnnotations.Schema;
Upvotes: 2
Views: 125
Reputation: 1391
What's confusing it, in effect, is that you have two ends for the relationship on Trip:
public Place Origin { get; set; }
public Place Destination { get; set; }
(which should also be virtual, BTW), and only one on Place:
public virtual ICollection<Trip> Trips { get; set; }
...so Entity Framework can't figure out which goes with what.
You need to add both a second navigation property to Place, and some data annotation attributes to tell Entity Framework how they relate to form the two halves of the many-to-many relationship. Omitting the other properties and the context for clarity, like this:
public class Trip
{
[InverseProperty ("AsOrigin")]
public virtual Place Origin { get; set; }
[InverseProperty ("AsDestination")]
public virtual Place Destination { get; set; }
}
public class Place
{
[InverseProperty ("Origin")]
public virtual ICollection<Trip> AsOrigin { get; set; }
[InverseProperty ("Destination")]
public virtual ICollection<Trip> AsDestination { get; set; }
}
If you need a single property on Place that gives you all trips that it's involved in, either as origin or destination, you can recreate it using the navigation properties like this:
[NotMapped]
public ICollection<Trip> Trips
{
get
{
return AsOrigin.Concat(AsDestination).Distinct();
}
}
Upvotes: 1
Reputation: 16149
I'm not a big fan of the relationships that you're creating here, but that's something for your DBA to chew on. In the meantime, if you want to do something like this, may I suggest utilizing the answer to this SO question which is trying to do something very similar. You would need to add a couple of more properties and set up foreign key relations between the tables, but it should work out just fine.
Upvotes: 0