我曾经在POCO中为多对多关系或关系ID生成所有帮助表,如UsergroupUsers
,但现在我希望EF能够处理它们。现在我认为这毕竟不是一个好主意。
当我尝试为特定用户获取所有UsergroupDynamicField
时,它会为每个用户组用户生成N+1
查询。
Here我通过简单地声明Usergroups
将是IQUeriable
而不是IEnumerable
来解决这个问题。现在我不能这样做,因为EF不会映射它,它必须是ICollection
。
public class User
{
...
public virtual ICollection<Usergroup> Usergroups { get; set; }
public IEnumerable<UserField> Fields
{
get
{
var fields = this.Usergroups.SelectMany(x => x.UsergroupDynamicFields); // N + 1 for every Usergroup
foreach (var field in fields)
{
yield return new UserField
{
Name = field.Name
};
}
}
}
}
答案 0 :(得分:1)
这里我通过简单地声明Usergroups将是IQUeriable而不是IEnumerable来克服这个问题。现在我不能这样做,因为EF不会映射它,它必须是ICollection。
但最终实施ICollection
的课程是EntityCollection<T>
。此集合有CreateSourceQuery()
function您可以使用:
var usergroupsQuery = ((EntityCollection<UserGroup>)this.Usergroups).CreateSourceQuery();
var fields = usergroupsQuery.SelectMany(x => x.UsergroupDynamicFields);
更新:正如评论中所指出的,只有在可以进行更改跟踪并启用更改跟踪时,才会使用ICollection<T>
实施EntityCollection<T>
(非密封类,以及所有相关内容)属性virtual
)。您可以用另一种方式创建查询:
var usergroupsQuery = db.Entry(this).Collection(u => u.Usergroups).Query();
var fields = usergroupsQuery.SelectMany(x => x.UsergroupDynamicFields);
请注意,这需要您以某种方式访问db
。
答案 1 :(得分:0)
我尝试使用像
这样的东西var res = c.Users.Include("Groups.DynFields").First().Groups.SelectMany(x => x.DynFields).ToList();
似乎没问题。我用的是EF5。
当然......这不是User类中的方法。它需要能够在DbSet对象上调用Include方法。
我希望这可能有所帮助。
完整的解决方案
public class User {
public Int32 Id { get; set; }
public String Name { get; set; }
public virtual ICollection<UserGroup> Groups { get; set; }
}
public class UserGroup {
public Int32 Id { get; set; }
public String Name { get; set; }
public virtual ICollection<User> Users { get; set; }
public virtual ICollection<UserGroupDynamicField> DynFields { get; set; }
}
public class UserGroupDynamicField {
public Int32 Id { get; set; }
public String Name { get; set; }
public virtual UserGroup Group { get; set; }
}
public class UserGroupDynFEFCFConfiguration : EntityTypeConfiguration<UserGroupDynamicField > {
public UserGroupDynFEFCFConfiguration()
: base() {
HasRequired(x => x.Group);
}
}
public class UserGroupEFCFConfiguration : EntityTypeConfiguration<UserGroup> {
public UserGroupEFCFConfiguration()
: base() {
HasMany(x => x.Users).WithMany(y => y.Groups);
}
}
public class TestEFContext : DbContext {
public IDbSet<User> Users { get; set; }
public IDbSet<UserGroup> Groups { get; set; }
public TestEFContext(String cs)
: base(cs) {
Database.SetInitializer<TestEFContext>(new DropCreateDatabaseAlways<TestEFContext>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new UserGroupDynFEFCFConfiguration());
modelBuilder.Configurations.Add(new UserGroupEFCFConfiguration());
}
}
class Program {
static void Main(String[] args) {
String cs = @"Data Source=ALIASTVALK;Initial Catalog=TestEF;Integrated Security=True; MultipleActiveResultSets=True";
using (TestEFContext c = new TestEFContext(cs)) {
UserGroup g1 = new UserGroup {
Name = "G1",
DynFields = new List<UserGroupDynamicField> {
new UserGroupDynamicField { Name = "DF11"},
new UserGroupDynamicField { Name = "DF12"}
}
};
c.Groups.Add(g1);
UserGroup g2 = new UserGroup {
Name = "G2",
DynFields = new List<UserGroupDynamicField> {
new UserGroupDynamicField { Name = "DF21"},
new UserGroupDynamicField { Name = "DF22"}
}
};
c.Groups.Add(g2);
c.Users.Add(new User {
Name = "U1",
Groups = new List<UserGroup> { g1, g2 }
});
c.SaveChanges();
}
using (TestEFContext c = new TestEFContext(cs)) {
var res = c.Users.Include("Groups.DynFields").First().Groups.SelectMany(x => x.DynFields).ToList();
foreach (var v in res) {
Console.WriteLine(v.Name);
}
}
}
}