Julien
Julien

Reputation: 282

Struggling with EF CodeFirst 1 to Many relationship

I would like to be able to tag my Movie with a Category.

public class Movie
{
   public virtual ObservableCollection<Category> Categories { get; set; }

   public void AddCategory(string name)
   {
       using (var dbContext = new MyDbContext())
       {
           var category = dbContext.Categories.SingleOrDefault(x => x.Name == name) ?? new Category(name, dbContext);
           Categories.Add(category);
           dbContext.SaveChanges();
       }
   }
}

public class Category()
{
    public Category(string name, DbContext dbContext)
    {
        Name = name;
        dbContext.Categories.Add(this);
        dbContext.SaveChanges();
    }
}

If the category does not exist, it is created and dbContext.Categories.Add(this) is called inside the Category c'tor.

There are no errors, but the new Category is not saved to my Movie.Categories.

I am guessing it is because my Movie class belongs to a different context? I am unsure how to structure this.

EDIT: If i was using a database first approach, this would result with a Movie_Categories table that has a Movie_Id and a Category_Id. Why is this so difficult?

Upvotes: 0

Views: 74

Answers (3)

Julien
Julien

Reputation: 282

code that ended up working

    public void AddCategory(string name)
    {
        Category category;

        using (var dbContext = new MyDbContext())
            category = dbContext.Categories.SingleOrDefault(x => x.Name == name);

        using (var dbContext = new MyDbContext())
        {
            if (category == null)
                category = new Category(name, dbContext);
            else
                dbContext.Categories.Attach(category);

            var movie = dbContext.Movies.Single(x => x.Id == Id);
            movie.Categories.Add(category);
            dbContext.SaveChanges();
        }
    }

Upvotes: 0

Praveen Paulose
Praveen Paulose

Reputation: 5771

I would structure the model differently. keep the dbcontext out of the model.

public class Movie
{
    public string Name { get; set; }
    public virtual ICollection<Category> Categories { get; set; }
}

public class Category
{
    public string Name {get;set;}
    public virtual ICollection<Movie> Movies {get;set;}
}

Notice that I have a virtual collection of Movies within Category. It is this property and the virtual collection in Movie that set the many to many relationship.

You can add then add the category to the collection directly and call SaveChanges.

using (var dbContext = new MyDbContext())
{
    var movie = dbContext.Movies.SingleOrDefault(x => x.Name == name);
    movie.Categories.Add(new Category() { Name = "Romance"});
    dbContext.SaveChanges();
}

The code above will be in some method outside the model classes, probably in your controller or your business layer.

Upvotes: 0

M.E.
M.E.

Reputation: 2931

I think what you really want is a many-to-many relationship: One movie can have many categories and also one category can belong to many movies.

So the Category class needs a public virtual ICollection<Movie> Movies {get; set; } property.

Your Movie class could look like this:

public class Movie
{
   public virtual ICollection<Category> Categories { get; set; }

   public void AddCategory(string name)
   {
       using (var dbContext = new MyDbContext())
       {
           // get the movie object from dbContext so that it is attached
           var movie = dbContext.Movies.SingleOrDefault(m => m.Name == Name); // or match Movie by Id instead of Name
           var category = dbContext.Categories.SingleOrDefault(x => x.Name == name) ?? new Category(name);
           movie.Categories.Add(category);

           dbContext.SaveChanges();
       }
   }
}

And the Category class:

public class Category
{
  public virtual ICollection<Movie>() Movies { get; set; }
  public string Name { get; set;}

  public Category(string name)
  {
    Name = name;
  }

}

Upvotes: 1

Related Questions