EF Code First无法为ICollection<string>生成表格。

14

我希望在我的一个数据类中(我们称之为“Foo”),有下面的ICollection属性

public class Foo
{
    [Key]
    public int FooId { get; set; }
    public string SomeValueOrOther { get; set; }
    public virtual ICollection<string> AllowedBars { get; set; }
}
我可以在使用实体上下文时添加字符串值,但它们不会“到达任何地方”。换句话说,没有生成表来表示此关系,因此也没有保存任何值。我期望的是一个有两列的表,一列为“FooId”,另一列为“AllowedBar”,并且EF会自动将其映射到集合中(就像在复杂类型中一样)。
由于这种情况未发生,所以我不得不创建一个名为“FooAllowedBar”的类,其中包含我上面描述的两个属性。
这使我很不满意,因为它是整个项目中唯一的“联接”类型类。当然它能够工作,所以一个成功的框已经勾选了,但是否有人知道如何让EF为字符串集合关系生成表格?(或int,datetime等等)
也许从EF的(仍然不多的)信息来看,这种类型的功能还没有被支持。但我只想接近一个明确的答案。
非常感谢提前的帮助, Rob
4个回答

18

EF只能使用实体类。每个实体类必须定义主键,因此在您的情况下最小限度为:

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

或者更糟糕

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

现在你可以定义一个StringData的集合来将其映射为相关表:

public virtual ICollection<StringData> AllowedBars { get; set; }

2
谢谢Ladislav,我一直暗自希望你能回答我的问题...然后你真的回答了!感谢你。 "EF只能使用实体类"——这就是我需要知道的全部。您是否认为应该增加此类功能?我经常需要在EF POCO的一部分中使用简单的字符串或int集合。 - LiverpoolsNumber9
@Ladislav 有没有办法扩展 EF 来提供自定义映射器,以便我可以自己转换集合?或者也许有一个我可以添加的属性,EF 将调用它? - uriDium
1
注意:生成的表将为上下文中任何实体中类型为“ICollection<StringData>”的每个属性添加一个外键列。 - Matthijs Wessels
当使用xml时,ICollection<>似乎不可序列化。有更好的集合吗?也许是List<>? - Jay

3

我知道在所有情况下这不是最佳实践,但我认为在某些情况下,在列中存储数组的逗号分隔列表是解决此问题的好方法。

条件包括:

  • 列表不会很长
  • 您不需要根据该列表中的值搜索实体

如果一个实体中有多个字符串列表会创建许多连接,那么这也可能是一个好主意。

在这些情况下,我将通过具有两个列表属性来解决它。一个是由EF使用的逗号分隔列表,另一个是在访问列表中的项目时可以使用的列表,如下所示:

[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();
        }
    }
}

在构造函数中,您需要将AllowedBars初始化为空列表。

您不需要使用[NotMapped]属性,因为这个集合不会被使用,但我认为这可以使意图更清晰。


有点喜欢这样 :) 感觉有点不太好,但我不在这里评判。 - LiverpoolsNumber9
理想情况下,字符串属性AllowedBarsList应该是一个隐藏的实现细节,但这在EF中不起作用。因此,它有点不太干净。 - Richard Garside

0

这样做行不通。原因是,在关系型数据库中,你不能真正地将数组或一组东西保存在字段中。由于类中的每个属性都将映射到数据库字段,因此集合的唯一方式是通过一对多关系。所以你需要连接(join)。因此,这不是EF的限制,而是关系型数据库的限制。

有些人通过将XML或CSV保存到表中的字符串字段来解决这个问题。但这被认为是非常糟糕的风格,所以不要这样做。我建议你只需接受连接(join)。它不会伤害任何人。


我知道你的意思,但我并不是试图将一个字符串数组保存到单个列中(当然,MSSQL数据库无法做到这一点),我正在尝试将多行保存到单个表中。我认为答案是“它本来就不是为此而设计的”(除非显式编写连接类)。 - LiverpoolsNumber9

-1
你没有适当地定义你的类表。假设你有两个表Foo和FooBar,它们之间存在一对多的关系。然后你需要按照以下方式定义这些类:
Foo
public class Foo
{
    public int FooId { get; set; }
    public string SomeValue { get; set; }

    public virtual ICollection<FooBar> FooBars { get; set; } 
}

FooBar

public class FooBar
{
    public int FooBarId { get; set; }
    public string SomeProperty { get; set; }
    public int FooId { get; set; }

    public virtual Foo Foo { get; set; } 
}

这将创建两个表,Foo有两列,FooBar有3列,包括FooId,表示Foo和FooBars之间的一对多关系。


1
这就是我所做的并且正在尝试避免的事情,但是对于将某些东西命名为“Foo foo”表示赞扬。 :) - LiverpoolsNumber9

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接