EF 4.1 Generic Many-To-Many关系

时间:2012-08-21 23:15:58

标签: c# .net generics entity-framework-4 ef-code-first

需要在EF 4.1中构建各种标记系统,允许查询每个标记的所有实体或每个实体的所有标记。这是我模型的缩略图:

public abstract class BaseEntity {

    [Required]
    [Key]
    public Guid ID { get; set; }
}

public class Tag : BaseEntity {
    // tag subscribers
    public List<King> Kings { get; set; }
    public List<Knight> Knights { get; set; }
    public List<Peasant> Peasants { get; set; }
}

public class King : BaseEntity {
    public string Title { get; set; }
    public List<Tag> Tags { get; set; }
}

public class Knight : BaseEntity {
    public string Title { get; set; }
    public List<Tag> Tags { get; set; }
}

public class Peasant : BaseEntity {
    public string Title { get; set; }
    public List<Tag> Tags { get; set; }
}

(是的,我知道King,Knight和Peasant在这里是一样的。但正如信使在Monty Python和圣杯中所说:“它只是一个模特。”)

所以无论如何,这个模型很好用,但我更喜欢T通用列表,而不是特定的演员。数据库中的表越少,从标签查询实体时的开销就越小。如何转换所有List&lt; Entity&gt; Tag中的属性为单个通用List&lt; T&gt;其中T:BaseEntity,这会导致我可以查询特定衍生物的单个查找表吗?类似的东西:

 List<Knight> knightsByTag = Tags.Where(t => t.GetType() == typeof (Knight)).ToList();

编辑: Yeesh。对不起,有一些实际的代码仍在那里。

@DarthVader:

  • 希望Tag使用一个List属性而不是当前的三个List属性。
  • 希望能够查询与骑士相关的所有标签,或与标签相关联的所有农民等。
  • 要确保EF CodeFirst能够准确地解析通用列表,最好使用查找表。

1 个答案:

答案 0 :(得分:1)

如果您想在BaseEntity中设置单个列表,则还必须删除子实体中的列表。你会以这样的结局结束:

public abstract class BaseEntity {
    ...

    // tags
    public List<Tag> Tags { get; set; }
}

public class Tag : BaseEntity {
    ...

    // tag subscribers
    public List<BaseEntity> Entities { get; set; }
}

如果您有任何特定约束,则必须在实体和标记之间建立关系之前在应用程序中检查它们。任何其他方式都会导致您为每个实体分离导航属性,并根据此类关系单独使用联结表。

与骑士相关的所有标签 - 这应该有效:

var tags = from k in context.Knights // or context.BaseEntities.OfType<Knight>()
           from t in k.Tags
           select t;

与标签相关联的所有农民 - 这应该有效:

var peasants = from t in context.Tags
               from p in t.Entities.OfType<Peasant>()
               select p;

请注意,映射继承会对查询性能产生负面影响。