Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework 6 and collections

I'm developing my first entity-framework app. I'm using EF vesion 6 (from Nuget) and .net 4.0. However, I'm having some difficulty with something that, to me, seems like it should be extraordinarily simple. I've found lots of conflicting advice and solutions on the internet, but after spending several days trying to work things out, I'm really confused and am to the point of questioning some basic understandings I have of the Entity Framework. What I want to do is this: create a simple collection of related entities, and automatically delete them when they're removed from the parent.

Here's how I would model this in vanilla C#. In keeping with Microsoft samples, assume we have two classes, Post and Tag, like so:

public class Post
{
    public string Name { get; set; }
    public string Author { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string Text { get; set; }
    // Possibly other properties here
}

Then, adding a tag is as simple as myPost.Tags.Add(myTag) and removing a tag is as simple as myPost.Tags.Remove(myTag).

Now to the Entity Framework side of things: I looked at that and thought "Foreign Key, of course!" but I had a host of issues adding a FK: Tags wouldn't delete from the database when they were removed from the post, myPost.Tags would have 0 elements when loaded from the db, despite the SQL explorer showing that the PostId value was correct, etc. I faffled around with a bunch of tricks, like marking the Tag.PostId as a Key, manually removing Tags, actually adding Tag to the context as a DbSet, manually setting myTag.Post = null; (I tried with Lazy loading both enabled and disabled, for what it's worth - though I'd like to keep it off if possible)

Now (thanks in no small part to seemingly conflicted and overly-complicated examples), I'm quite confused and lost. Can someone tell me exactly how I should go about setting this relationship up in EF? (I'm using Code First, by the way)

SOLUTION:

Thanks to Moho, I've come up with this structure, which does exactly what I want:

public class Post
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }

    public virtual ICollection<Tag> Tags { get; set; }

    public Post()
    {
        Tags = new HashSet<Tag>();
    }
}

public class Tag
{
    [Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Text { get; set; }
    // Possibly other properties here

    public virtual Post Post { get; set; }
    [Key, Column(Order=2)]
    public virtual int PostId { get; set; }
}

public class TestContext : DbContext
{
    public DbSet<Post> Posts { get; set; }
}

When a Tag is removed from a Post's Tags collection, Entity Framework will issue a DELETE for the tag, as outlined here (#2): http://www.kianryan.co.uk/2013/03/orphaned-child/

Likewise, adding a tag to a post will automatically issue an INSERT and set the FK relationship.

One thing to note: Make sure you use virtual! I think that was the root of a lot of my frustration as well.

like image 814
Xcelled Avatar asked Dec 17 '13 04:12

Xcelled


People also ask

What is difference between Entity Framework 5 and 6?

EF5 is built into the core of . NET 4.5, whereas EF6 has been shifted out, and is open source. This means that you must add the new EF6 assemblies to all of the relevant projects in the solution, in particular the entry project. This means that you must remove assembly System.

Which of the features is are now supported in EF Core 6?

EF Core now supports: The creation of temporal tables using Migrations. Transformation of existing tables into temporal tables, again using Migrations. Querying historical data.

What are the three types of Entity Framework?

There are three approaches to model your entities in Entity Framework: Code First, Model First, and Database First. This article discusses all these three approaches and their pros and cons.

How will you create relationship between tables in Entity Framework?

You can create such a relationship by defining a third table, called a junction table, whose primary key consists of the foreign keys from both table A and table B.


2 Answers

Try also defining the relationship from the Tag side as well, specifying each Tag relates to a single Post and is required.

Add a required navigation property to Post in Tag:

public class Tag
{
    // you need an ID
    public int Id { get; set; }

    public string Text { get; set; }

    [Required]
    public virtual Post Post { get; set; }
}

Alternatively, if you really don't want to add the navigation property, you can use the Fluent API:

modelBuilder.Entity<Post>().HasMany( p => p.Tags ).WithRequired();
like image 188
Moho Avatar answered Sep 21 '22 00:09

Moho


This is probably thread necromancy, but I don't have the rep to just comment. Wouldn't the following do what you need?

public class Tag
{
    [Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Text { get; set; }
    // Possibly other properties here

    public int PostId { get; set; }

    [ForeignKey("PostId")]
    public virtual Post Post { get; set; }

}

PostId is loaded from the database, then used as the Foreign Key (via the annotation) into the Post class. Post is virtual, nothing else is. You could probably just go with the basic [Key] annotation too.

like image 23
Hecatonchires Avatar answered Sep 20 '22 00:09

Hecatonchires