如何强制Entity Framework映射“internal”导航属性?

3

使用EF 5.0Code First,我有以下内容:

internal class Entities : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Project> Projects { get; set; }
}

// User class which holds a list of 'Project' class
public class User
{
    private List<Project> _projects = new List<Project>();

    public int Id { get; set; }
    internal List<Project> Projects
    {
        get { return _projects; }
        set { _projects = value; }
    }
}

// Project class which holds a list of 'Milestone' class
public class Project
{
    private List<Milestone> _milestones = new List<Milestone>();

    public int Id { get; set; }
    public string Title { get; set; }
    internal List<Milestone> MileStones
    {
        get { return _milestones; }
        set { _milestones = value; }
    }
}

尽管EF已经正确地创建了表和关系(User=>Project=>Milestone的一对多关系),但如果我创建一个带有一些项目的用户并将其添加到DbContext中,只有用户会被添加,而他的项目则不会。对于具有里程碑的项目的用户也是如此。我是这样做的:
public void AddUser(User user)
{
    using (var repository = new Entities())
    {
        repository.Users.Add(user);
        repository.SaveChanges();
    }
}

我的问题是如何强制EF自动插入或更新复杂实体(级联),因此添加一个带有项目列表的用户,可以自动将用户插入到USERS表中,并将其项目与正确的关系自动插入到PROJECTS表中? EF在其第5个版本中是否如此智能,还是我应该手动操作?

你是否尝试将 Setter 设置为 private - Justin
@Justin:那不起作用。尽管我不想这样做,但我甚至将其设置为“public IReadOnlyList”和“public IReadOnlyCollection”,但“EF”仍然拒绝映射只读属性。 - Xaqron
你能将它们公开并修改get/set以包含你的验证逻辑吗? - Justin
@Justin:一旦我返回该集合(此处为列表),我就无法进行修改,除非我将其限制为只读集合。 - Xaqron
你能再解释一下为什么你无法进行修改吗? - Justin
@Justin:返回MyList.AsReadOnly()IList属性是可行的,但我并不需要我的列表只读。当它是私有或内部时,我需要EF进行映射。回答你的问题:列表是引用类型,如果直接返回它们(除非作为只读集合),它们可以直接修改。 - Xaqron
3个回答

4
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().HasMany(x => x.Projects);
}

这给了你你想要的东西吗? - Justin
@Justin:是的,这个可以正常工作,不需要将“internal”改为“public”。 - Xaqron

3
您可以通过将“List Projects”和“List MileStones”属性设置为“protected internal”来实现所需的结果。这样,EF就可以处理它们。EF会使用代理类包装器覆盖这些属性,并且您还将拥有延迟加载功能。

0

别担心,EF很聪明,但是当导航属性的访问权限设置为internal时,它将无法添加。将它们改为public,你的项目/里程碑就会被添加。

// User class
public List<Project> Projects
{
    get { return _projects; }
    set { _projects = value; }
}

// Project class
public List<Milestone> MileStones
{
    get { return _milestones; }
    set { _milestones = value; }
}

此外,如果您想在导航属性上启用延迟加载,您还需要将它们设置为public virtual,因为EF内部必须为您的模型类创建代理。

它们被标记为“internal”的原因是:在允许添加/删除项目/里程碑之前,我需要进行一些检查,因此隐藏了列表并提供了两个函数(AddProject / RemoveProject),(AddMilestone / RemoveMilestone)以实现此目的。是否有任何方法可以向EF发出信号,使其像它们是“public”一样工作? - Xaqron
我不这么认为,EF需要访问它们来在检索/更新数据库时设置/获取您的导航属性。 - Alaa Masoud
2
EF 可以访问它们,因为代码引用了 EF。但是我需要隐藏这些列表使其不被直接修改,并提供一些方法来访问它们。有没有任何数据注释可以强制 EF 将它们视为 Public?实际上我应该将它们设为 Private,但由于某些原因将它们设为了 Internal - Xaqron
1
这样使用 Code FirstEF 就失去了它的优势。我使用它是为了少写代码而不是更多。无论如何,感谢提示 +1。 - Xaqron
1
@AlaaMasoud 这里的问题在于,在这种情况下,EF阻止了正确的封装,这在我的书中是对OO原则的严重违反。 - Kugel
显示剩余2条评论

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