EF4.1代码先一对多自我引用



我试图首先使用EF4.1代码进行一对多的自我引用。我的实体看起来像这样

public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Sitename { get; set; }
    public virtual Site ChildSite { get; set; }
    public virtual ICollection<Site> ChildSites { get; set; }
}
在我的context类中,我这样做是为了让self引用
modelBuilder.Entity<Site>()
    .HasOptional(s => s.ChildSite)
    .WithMany(s => s.ChildSites)
    .HasForeignKey(s => s.ParentId);

但是当我尝试添加一些虚拟数据到我的数据库与此代码

var sites = new List<Site>
{
    new Site { ParentId = 0, Sitename = "Top 1" },
    new Site { ParentId = 0, Sitename = "Top 2" },
    new Site { ParentId = 0, Sitename = "Top 3" },
    new Site { ParentId = 0, Sitename = "Top 4" },
    new Site { ParentId = 1, Sitename = "Sub 1_5" },
    new Site { ParentId = 1, Sitename = "Sub 1_6" },
    new Site { ParentId = 1, Sitename = "Sub 1_7" },
    new Site { ParentId = 1, Sitename = "Sub 1_8" },
    new Site { ParentId = 2, Sitename = "Sub 2_9" },
    new Site { ParentId = 2, Sitename = "Sub 2_10" },
    new Site { ParentId = 2, Sitename = "Sub 2_11" },
    new Site { ParentId = 2, Sitename = "Sub 2_12" },
    new Site { ParentId = 3, Sitename = "Sub 3_13" },
    new Site { ParentId = 3, Sitename = "Sub 3_14" },
    new Site { ParentId = 3, Sitename = "Sub 3_15" },
    new Site { ParentId = 3, Sitename = "Sub 3_16" },
    new Site { ParentId = 4, Sitename = "Sub 4_17" },
    new Site { ParentId = 4, Sitename = "Sub 4_18" },
    new Site { ParentId = 4, Sitename = "Sub 4_19" },
    new Site { ParentId = 4, Sitename = "Sub 4_20" }
};
sites.ForEach(s => context.Sites.Add(s));
context.SaveChanges();

我得到这个错误:

无法确定的主端"Cms.Model。Site_ChildSite"关系。多个添加的实体可以有相同的主键

我错过了什么?

编辑:

这是我的问题的解决方案。我从实体 中删除了public virtual Site ChildSite { get; set; }
public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Sitename { get; set; }
    public virtual ICollection<Site> ChildSites { get; set; }
}

然后将modelBuilder更改为

modelBuilder.Entity<Site>()
    .HasMany(s => s.ChildSites)
    .WithOptional()
    .HasForeignKey(s => s.ParentId);

由于自动生成数据库似乎不起作用,我继续自己创建表,如下所示

int Id, not null, primary key
int ParentId, null
string Sitename, null

一切都如我所愿。

2日编辑

最后一步是让虚拟数据自动生成工作

var parent1 = new Site
{
    Sitename = "Top 1",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 1_5"},
            new Site {Sitename = "Sub 1_6"},
            new Site {Sitename = "Sub 1_7"},
            new Site {Sitename = "Sub 1_8"}
        }
};
ect . . . 
context.Sites.Add(parent1);
context.SaveChanges();

参见下面的Slauma答案

我有一个不同的模型,但我会在我的情况下张贴必要的东西,它在MVC 3上与EF4.1一起工作很好:

public class Page
{
    public int Id { get; set; }
    public virtual string Title { get; set; }
    public int? ParentId { get; set; }
    public virtual Page Parent { get; set; }
    public virtual ICollection<Page> Children { get; set; }
}

数据库(使用fluent API)

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
     modelBuilder.Entity<Page>()
                 .HasOptional(s => s.Parent)
                 .WithMany(s => s.Children)
                 .HasForeignKey(s => s.ParentId);
}
<<p> 初始化/strong>
var page1 = new Page()
{
     Title = "title"
};
context.Pages.Add(page1);
var page2 = new Page()
{
      Parent = page1,
      Title = "title2",
};
context.Pages.Add(page2);

您的映射是正确的,您不需要删除ChildSite属性。当你创建实体时,你不能使用外键属性,"猜测"这些自动生成的数字在实体存储后会是什么样子,并在存储的相同实体中使用这些数字。

下面的命令应该可以工作并在数据库中创建预期的行:

var parent1 = new Site
{
    Sitename = "Top 1",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 1_5"},
            new Site {Sitename = "Sub 1_6"},
            new Site {Sitename = "Sub 1_7"},
            new Site {Sitename = "Sub 1_8"}
        }
};
var parent2 = new Site
{
    Sitename = "Top 2",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 2_9"},
            new Site {Sitename = "Sub 2_10"},
            new Site {Sitename = "Sub 2_11"},
            new Site {Sitename = "Sub 2_12"}
        }
};
var parent3 = new Site
{
    Sitename = "Top 3",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 3_13"},
            new Site {Sitename = "Sub 3_14"},
            new Site {Sitename = "Sub 3_15"},
            new Site {Sitename = "Sub 3_16"}
        }
};
var parent4 = new Site
{
    Sitename = "Top 4",
    ChildSites = new List<Site>
        {
            new Site {Sitename = "Sub 4_17"},
            new Site {Sitename = "Sub 4_18"},
            new Site {Sitename = "Sub 4_19"},
            new Site {Sitename = "Sub 4_20"}
        }
};
context.Sites.Add(parent1);
context.Sites.Add(parent2);
context.Sites.Add(parent3);
context.Sites.Add(parent4);
context.SaveChanges();

编辑

如果由外键表示的实体存在于数据库中,您可以使用它-例如:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
site.ParentId = 4; // set a parent for "Top 1"
context.SaveChanges();

添加新子元素:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
site.ChildSites.Add(new Site { Sitename = "Sub 1_9" });
context.SaveChanges();

删除子元素:

var site = context.Sites.Single(s => s.Sitename == "Top 1");
// works because of lazy loading
var childToRemove = site.ChildSites.Single(s => s.Sitename == "Sub 1_9");
site.ChildSites.Remove(childToRemove);
context.SaveChanges();

等。

首先-不要指定id -我认为数据库负责为您的实体添加自动编号。

试着这样填充你的数据库:

var top1 = new Site { Sitename = "Top 1" };
var sub15 = new Site { ChildSite = top1 , Sitename = "Sub 1_5" };
var sub16 = new Site { ChildSite = top1 , Sitename = "Sub 1_6" };
var sub17 = new Site { ChildSite = top1 , Sitename = "Sub 1_7" };
...
context.Sites.Add(top1);
var top2 = new Site { Sitename = "Top 2" };
var sub29 = new Site { ChildSite = top2 , Sitename = "Sub 2_9" };
var sub210 = new Site { ChildSite = top2 , Sitename = "Sub 2_10" };
var sub211 = new Site { ChildSite = top2 , Sitename = "Sub 2_11" };
....
context.Sites.Add(top2);
....
context.SaveChanges();

下一个:我认为你应该为ParentSite调用你的ChildSite,这将使代码更容易阅读:

var top1 = new Site { Sitename = "Top 1" };
var sub15 = new Site { ParentSite = top1 , Sitename = "Sub 1_5" };
var sub16 = new Site { ParentSite = top1 , Sitename = "Sub 1_6" };
var sub17 = new Site { ParentSite = top1 , Sitename = "Sub 1_7" };
...
context.Sites.Add(top1);
var top2 = new Site { Sitename = "Top 2" };
var sub29 = new Site { ParentSite = top2 , Sitename = "Sub 2_9" };
var sub210 = new Site { ParentSite = top2 , Sitename = "Sub 2_10" };
var sub211 = new Site { ParentSite = top2 , Sitename = "Sub 2_11" };
....
context.Sites.Add(top2);
....
context.SaveChanges();

不知道为站点保留ChildSiteChildSites的集合的目的是什么。试试这个配置。

public class Site
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
     public virtual  Site Parent { get; set; }
    public string Sitename { get; set; }
    public virtual ICollection<Site> ChildSites { get; set; }
}
modelBuilder.Entity<Site>()
    .HasOptional(s => s.Parent)
    .WithMany(s => s.ChildSites)
    .HasForeignKey(s => s.ParentId);

编辑当你插入时,你需要这样做。

 site s1=   new Site { ParentId = 0, Sitename = "Top 1" };
 site s2=   new Site { ParentId = 0, Sitename = "Top 2" };
 site s3=   new Site { ParentId = 0, Sitename = "Top 3" };
//....
 site s4=  new Site { Parent = s1, Sitename = "Sub 1_5"};

最新更新