Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Code First not generating table for ICollection<string>

I would like the below ICollection property in one of my data classes (let's call it "Foo")

public class Foo
{
    [Key]
    public int FooId { get; set; }
    public string SomeValueOrOther { get; set; }
    public virtual ICollection<string> AllowedBars { get; set; }
}

I can add the string values when using the entity context, but they don't "go anywhere". In other words, no table is generated to represent this relationship and therefore no values are saved. What I would expect is a table with two columns, one for "FooId" and one for "AllowedBar" and for EF to map this to the collection automatically (as it does in with complex types).

As this doesn't happen, I've had to create a class called "FooAllowedBar" with the two properties I've described above.

This displeases me because it's the only "join" type class I have in the entire project. It works, of course, so one box is ticked, but does anybody know of a way to get EF to generate a table for the string collection relationship? (Or int, or datetime etc etc)

It may well be, from the little info that's out there on EF (still!) that this type of functionality is not (yet) supported. By I'd just like to get close to a definitive answer.

Many thanks in advance, Rob

like image 333
LiverpoolsNumber9 Avatar asked Nov 20 '11 13:11

LiverpoolsNumber9


2 Answers

EF can only work with entity classes. Each entity class must have defined primary key so the minimum in your scenario is:

public class StringData
{
    public int Id { get; set; }
    public string Data { get; set; }
}

or worse

public class StringData
{
    [Key]
    public string Data { get; set; }
}

Now you can define collection of StringData to map it as related table:

public virtual ICollection<StringData> AllowedBars { get; set; }
like image 196
Ladislav Mrnka Avatar answered Nov 12 '22 06:11

Ladislav Mrnka


I know this is not best practice in all cases, but I think there are cases where storing a comma seperated list of your array in a column is a good way to solve this problem.

Conditions include:

  • The list is not going to be long
  • You don't need to search for entities based on the values in that list

It could also be a good idea if one entity has multiple string lists in it that would create lots of joins.

In those cases I would solve it by having two properties for the list. One being the comma seperated list used by EF and the other a list that you can use when accessing the items in the list like this:

[NotMapped]
public List<String> AllowedBars { get; set; }

/// <summary>
/// Comma seperated list of AllowedBars
/// </summary>
public String AllowedBarsList
{
    get { return String.Join(",", AllowedBars); }
    set
    {
        if (String.IsNullOrWhiteSpace(value))
        {
            AllowedBars.Clear();
        }
        else
        {
            AllowedBars = value.Split(',').ToList();
        }
    }
}

You need to initialise AllowedBars to be an empty list in the constructor.

You don't need to use the [NotMapped] attribute as this collection won't be used anyway, but I think it makes the intent clearer.

like image 3
Richard Garside Avatar answered Nov 12 '22 08:11

Richard Garside