Reputation: 2711
I have these three entities:
public class Dog
{
public int DogId { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool Checked { get; set; }
public string DogImage { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
public class Event
{
public int EventId { get; set; }
public string EventName { get; set; }
public string EventLocation { get; set; }
public string EventType { get; set; }
public string EventDate { get; set; }
public virtual ICollection<Result> Results { get; set; }
}
public class Result
{
public int ResultId { get; set; }
public int Track { get; set; }
public int Obedience { get; set; }
public int Protection { get; set; }
[ForeignKey("Dog")]
public int DogId { get; set; }
public virtual Dog Dog { get; set; }
[ForeignKey("Event")]
public int EventId { get; set; }
public virtual Event Event { get; set; }
}
I´ve been getting help from here before in order to set it up like this. Entity Framework errors when trying to create many-to-many relationship
So the way it is now I guess the result
is the "glue" that ties these classes together containing foreign keys to the two other tables.
What I have been trying to achieve for days now is to:
Lets say I create an event like this:
[HttpPost]
public ActionResult CreateEvent(Event newEvent)
{
newEvent.EventDate = newEvent.EventDate.ToString();
_ef.AddEvent(newEvent);
return View();
}
Now I guess the next step would be to add a list of dogs to this event and in order to do that I need to somehow use my result-class since that's the "glue"-class. Please let me know if I'm even on the right track here.
Upvotes: 0
Views: 139
Reputation: 14417
It is not really a good idea to do many to many relationships like how you've done. See here
In order to get a proper many to many relationship, mapped in the proper way in the database, that doesn't have pitfalls, I would try it this way:
public class Dog {}
public class Event {}
public class Result {}
// This is a linking table between Dog and Results
public class DogResult
{
public int Id {get;set;}
public int DogId {get;set;}
public int ResultId {get;set;}
}
// This is a linking table between Events and Results
public class EventResult
{
public int Id {get;set;}
public int EventId {get;set;}
public int ResultId {get;set;}
}
When you now write your query you can do this:
using (var context = new DbContext())
{
var dogs = context.Dogs();
var dogResults = context.DogResults();
var results = context.Results();
var dogsAndResults = dogs.Join(
dogResults,
d => d.Id,
r => r.DogId,
(dog, dogResult) => new { dog, dogResult })
.Join(
results,
a => a.dogResult.ResultId,
r => r.Id,
(anon, result) => new { anon.dog, result });
}
It is a bit nasty looking, but it will give you back a list of anonymous objects containing a Dog
and its related Result
. But obviously it would be better to do this in a stored proc:
using (var context = new DbContext())
{
var results = context.Database.ExecuteStoreQuery<SomeResultDto>("SELECT * .... JOIN ... ");
}
This is cleaner, because you are using SQL.
This is a more complex way of dealing with it. But far more performant, especially if you understand fully how entity framework executes LINQ.
Obviously if you want to create these links:
using (var context = new DbContext())
{
context.Dogs.AddRange(dogs); // dogs being a list of dog entities
context.Results.AddRange(results); // events being a list of results entities
context.DogResults.AddRange(dogResults); // a list of the links
}
It is completely up to you how you create these links. To turn this into a sproc as well, you want to create some custom User Defined Table Types and use them as a Table Value Parameter.
var dogResults = dogs.SelectMany( d => results.Select ( r => new DogResult { DogId = d.Id, ResultId = r.Id } ) );
That is a beast of a LINQ query and basically it gets every dog and links it to every result. Run it in LinqPad and Dump
the values.
Upvotes: 1
Reputation: 1471
I've only done this using the fluent method (when I was learning I found you can do everything in fluent, but not with annotations, so I've not looked into them), the following creates a many to many between my Unit
entity and my UnitService
entity:
modelBuilder.Entity<Unit>()
.HasMany<UnitService>(u => u.Services)
.WithMany(us => us.Units);
This code is in the protected override void OnModelCreating(DbModelBuilder modelBuilder)
method.
In your case Event
is Unit
and Dog
is UnitService
.
Oh ooops, you don't need that at all, your 'join' table is your results table, in my case I don't care about the join table so its all hidden. Maybe something like:
modelBuilder.Entity<Result>()
.HasMany<Event>(e => e.Results);
modelBuilder.Entity<Result>()
.HasMany<Dog>(d => d.Results);
Upvotes: 1