我试图首先使用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();
不知道为站点保留ChildSite
和ChildSites
的集合的目的是什么。试试这个配置。
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"};