Entity framework 首先更新多对多关系既不完全是代码也不完全是数据库
我似乎在为命名约定和理解的结合而挣扎 我继承了一个数据库,正在构建一个MVC站点,但我无法让“数据库优先”工作流很好地发挥作用。最后,我手动构建了我的上下文类,并且一直在愉快地工作 我现在的情况是,我无法添加一个与其他几个现有实体(多对多)有关系的实体 我的数据库看起来(这个问题简化了)如下所示:Entity framework 首先更新多对多关系既不完全是代码也不完全是数据库,entity-framework,asp.net-mvc-4,ef-database-first,Entity Framework,Asp.net Mvc 4,Ef Database First,我似乎在为命名约定和理解的结合而挣扎 我继承了一个数据库,正在构建一个MVC站点,但我无法让“数据库优先”工作流很好地发挥作用。最后,我手动构建了我的上下文类,并且一直在愉快地工作 我现在的情况是,我无法添加一个与其他几个现有实体(多对多)有关系的实体 我的数据库看起来(这个问题简化了)如下所示: ListItem Option OptionListItems ====== ====== =============== Id
ListItem Option OptionListItems
====== ====== ===============
Id Id ListItem_Id
Name Name Option_Id
public virtual DbSet<OptionListItem> OptionListItems { get; set; }
我的上下文包含一个属性,该属性允许我获取所有列表项:
public virtual DbSet<ListItem> ListItems { get; set; }
事实上,我必须在数据库中手动构造交叉引用表,这是我在尝试运行上述查询时所做的,异常情况告诉我没有名为dbo.OptionListItems
的对象。所以我认为我们都很好
现在我需要创建一个新的列表项
,并将其链接到一个或多个现有的选项
,我不知所措
一旦我单独创建了新的ListItem
,并尝试调用ListItem.Options.Add(…)
,它就会失败,但如果我尝试获取对特定选项的引用并尝试执行Option.ListItems.Add(…)
,我也会得到完全相同的异常
这个错误有点有趣,与我的表名相反:
{"Invalid object name 'dbo.ListItemOptions'."}
我怀疑在我的上下文上构建一个类型和一个属性来直接访问交叉引用表(如下所示)违背了EF的本质:
ListItem Option OptionListItems
====== ====== ===============
Id Id ListItem_Id
Name Name Option_Id
public virtual DbSet<OptionListItem> OptionListItems { get; set; }
公共虚拟数据库集选项列表项{get;set;}
但是,我完全被创建新关系的模式所迷惑。我们有一个(多对多)声明式的工作模式。伪代码:
public class ListItem
{
public ListItem()
{
this.RelatedOptions = new HashSet<OptionListItems>();
}
[Key]
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<OptionListItems> RelatedOptions {get; set;}
}
public class Option
{
public Ortion()
{
this.RelatedItems = new HashSet<OptionListItems>();
}
[Key]
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<OptionListItems> RelatedItems {get; set;}
}
public class OptionListItems
{
[Key]
public int Id {get; set;}
[Column("ListItemId", Order = 1)]
[ForeignKey("ParentListItem")]
public int ListItemId {get; set;}
[Column("OptionId", Order = 2)]
[ForeignKey("ParentOption")]
public int OptionId {get; set;}
public virtual ListItem ParentListItem {get; set;}
public virtual Option ParentOption {get; set;}
}
公共类列表项
{
公共列表项()
{
this.relatedpoptions=newhashset();
}
[关键]
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection RelatedOptions{get;set;}
}
公共类选项
{
公共奥尔顿()
{
this.RelatedItems=新HashSet();
}
[关键]
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection RelatedItems{get;set;}
}
公共类选项列表项
{
[关键]
公共int Id{get;set;}
[列(“ListItemId”,顺序=1)]
[外键(“父项列表项”)]
公共int ListItemId{get;set;}
[列(“OptionId”,顺序=2)]
[外键(“父选项”)]
public int OptionId{get;set;}
公共虚拟ListItem ParentListItem{get;set;}
公共虚拟选项ParentOption{get;set;}
}
这应该以声明的方式创建完整的关系我们可以以声明的方式(多对多)工作。伪代码:
public class ListItem
{
public ListItem()
{
this.RelatedOptions = new HashSet<OptionListItems>();
}
[Key]
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<OptionListItems> RelatedOptions {get; set;}
}
public class Option
{
public Ortion()
{
this.RelatedItems = new HashSet<OptionListItems>();
}
[Key]
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<OptionListItems> RelatedItems {get; set;}
}
public class OptionListItems
{
[Key]
public int Id {get; set;}
[Column("ListItemId", Order = 1)]
[ForeignKey("ParentListItem")]
public int ListItemId {get; set;}
[Column("OptionId", Order = 2)]
[ForeignKey("ParentOption")]
public int OptionId {get; set;}
public virtual ListItem ParentListItem {get; set;}
public virtual Option ParentOption {get; set;}
}
公共类列表项
{
公共列表项()
{
this.relatedpoptions=newhashset();
}
[关键]
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection RelatedOptions{get;set;}
}
公共类选项
{
公共奥尔顿()
{
this.RelatedItems=新HashSet();
}
[关键]
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection RelatedItems{get;set;}
}
公共类选项列表项
{
[关键]
公共int Id{get;set;}
[列(“ListItemId”,顺序=1)]
[外键(“父项列表项”)]
公共int ListItemId{get;set;}
[列(“OptionId”,顺序=2)]
[外键(“父选项”)]
public int OptionId{get;set;}
公共虚拟ListItem ParentListItem{get;set;}
公共虚拟选项ParentOption{get;set;}
}
这应该以声明的方式建立完整的关系史蒂夫·格林为我指明了正确的方向,这是值得赞扬的。
当我使用.Include(p=>p.Options)
查询WorkItem
时,我使用的表是按照约定创建的,并且工作正常。但是,如果您尝试进行更新,约定似乎会崩溃。我不确定为什么,但在查询时映射表的构造似乎是++s
,但在更新时却是++s
好消息是,通过使用fluentAPI,我在实体之间创建了一个特定的映射,并强制执行交叉引用表,查询和更新都可以工作
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ListItem>()
.HasMany<Option>(s => s.Options)
.WithMany(c => c.ListItems)
.Map(cs =>
{
cs.MapLeftKey("ListItem_Id");
cs.MapRightKey("Option_Id");
cs.ToTable("OptionListItems");
});
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(s=>s.Options)
.WithMany(c=>c.ListItems)
.Map(cs=>
{
cs.MapLeftKey(“列表项_Id”);
cs.MapRightKey(“选项Id”);
cs.ToTable(“期权清单”);
});
}
史蒂夫·格林为我指明了正确的方向,这值得赞扬。
当我使用.Include(p=>p.Options)
查询WorkItem
时,我使用的表是按照约定创建的,并且工作正常。但是,如果您尝试进行更新,约定似乎会崩溃。我不确定为什么,但在查询时映射表的构造似乎是++s
,但在更新时却是++s
好消息是,通过使用fluentAPI,我在实体之间创建了一个特定的映射,并强制执行交叉引用表,查询和更新都可以工作
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ListItem>()
.HasMany<Option>(s => s.Options)
.WithMany(c => c.ListItems)
.Map(cs =>
{
cs.MapLeftKey("ListItem_Id");
cs.MapRightKey("Option_Id");
cs.ToTable("OptionListItems");
});
}
模型创建时受保护的覆盖无效(DbModelBuilder modelBuilder)
{
modelBuilder.Entity()
.HasMany(s=>s.Options)
.WithMany(c=>c.ListItems)
.Map(cs=>
{
cs.MapLeftKey(“列表项_Id”);
cs.MapRightKey(“选项Id”);
cs.ToTable(“期权清单”);
});
}
不确定如何删除DB first的内容,但如果需要控制多对多,则需要使用流畅的地图代码(靠近底部)。是的,这是一种奇怪的情况。我有一个DB和一些手动创建的POCO,所以在上面我添加了位t