SushiDynamite
SushiDynamite

Reputation: 143

Adding tag list dropdown to C# entity class - StackOverflow type

I have a class named Question in which I would like to have some tags from dropdown list for easier searching, tags would be in separate class because I would like to add them separately.

First class Question:

public int Id { get; set; }
public string Description { get; set; }

Second class Tag:

public int Id { get; set; }
public string Name { get; set; }

What is the best way to implement that? Something like when posting question here on SO and adding tags below.

I'm using C# MVC5 with entity-framework for now. Many-to-many relationship table maybe?

Upvotes: 2

Views: 667

Answers (2)

Harald Coppoolse
Harald Coppoolse

Reputation: 30474

So you have some Questions, and every Question has zero or more Tags. Similarly, the same Tag may be used by zero or more Questions.

This is a true many-to-many relationship. Normally you would configure an entity framework many-to-many relationship as following

class Question
{
    public int Id {get; set;}    // will become primary key

    // every Question has zero or more Tags
    public virtual ICollection<Tag> Tags {get; set;}

    // other properties:
    public string Text {get; set;}
    ...
}

class Tag
{
    public int Id {get; set;}    // will become primary key

    // every Tag is used by zero or more Questions
    public virtual ICollection<Question> Questions {get; set;}

    // other properties:
    public string Text {get; set;}
    ...
}
public MyDbContext : DbContext
{
    public DbSet<Question> Questions {get; set;}
    public DbSet<Tag> Tags {get; set;}
}

This is all that entity framework needs to know that you meant to configure a many-to-many relationship. Entity Framework will create and maintain the proper junction table with the correct foreign keys for you. You won't use this junction table, you will use the ICollections.

One extra: you probably don't want two Tags with the same name, so let's guarantee uniqueness by putting them in an Index.

in your DbContext.OnModelCreating:

public overrid void OnModelCreating(...)
{
    // The Tag.Text must be unique, we put it in an Index
    modelBuilder.Entity<Tag>()
        .Property(tag => tag.Text)
        .HasUniqueIndexAnnotation("IndexTagText", 0)
}

Every time the Tag.Text changes, the index is updated and it is checked whether the Updated Text is not already used. Another advantage: lookup by Text has become faster

Now you want a Dropdown list that contains all existing Tags:

var allTags = myDbContext.Tags
    .Select(tag => new DisplayableTag()
    {
        TagId = tag.Id,
        Display = tag.Text,
    })
    .OrderBy(tag => tag.Text)    // an ordered drop down look nicer
    .ToList();

The creatin of the DrowDown is probably done by visual studio designer. Code will be like:

// create a BindingSource that binds DisplayableTag objects:
BindingSource bindingSource1 = new BindingSource(this.components);
bindingSource1.DataSource = typeof(DisplayableTag);

// create a ListBox (or if you want: a dropdown ComboBox)
// bind it to the bindingSource
ListBox listBox = new ListBox();
listBox.DataSource = bindingSource1;
listBox.DisplayMember = "Display";
listBox.SelectionMode = SelectionMode.MultiSimple; // multiple tags can be selected

Now, whenever an item from the BindingSource needs to be displayed, the value of DisplayableTag.Display will be shown, which is the original Tag.Text

Now suppose the operator selects several Displayed tags and presses the Questions button to display all Questions with these Tags:

private void button1_Click(object sender, EventArgs e)
{
    IEnumerable<int> selectedTagIds = this.ListBox1.SelectedItems
        .Select(item => item.TagId);

    this.DisplayQuestionsWithTags(selectedTagIds);
}

Upvotes: 1

Adnan Niloy
Adnan Niloy

Reputation: 469

Modify your Question class as below:

public int Id { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }

By adding public virtual ICollection<Tag> Tags { get; set; } in the class, you can add the list of selected tags against any question.

Upvotes: 2

Related Questions