首先使用 Entity Framework 代码与联结 table 建立一对多关系
One to many relationship with junction table using Entity Framework code first
我首先使用 EF6 代码创建数据库,然后努力使用联结创建一对多关系 table。
这是我正在尝试做的一个例子:
Foo
个实体可以包含任意数量 (0-n) 个 Bar
个实体,但是 Bar
个实体不一定属于 Foo
个。我可能希望不同类型的实体也包含一个或多个 Bar
,因此 Bar
不包含其父项的外键很重要。
所以连接 table 会像这样:
Name | FooBar
------------|-------
Primary Key | BarID
Key | FooID
因此,如果我们按如下方式创建实体:
public class Foo
{
public long ID { get; set; }
public ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public long ID { get; set; }
}
然后配置它们:
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
HasKey(p => p.ID);
HasMany(p => p.Bars)
.WithRequired()
.Map(m => {
m.ToTable("FooBar");
m.MapKey("FooKey");
});
}
但这会导致抛出以下异常:
An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code. Additional information: The specified table 'FooBar' was not found in the model. Ensure that the table name has been correctly specified.
不幸的是,我不确定这意味着什么 - 我需要创建一个单独的 FooBar
实体吗?
如何配置这些实体以便正确创建连接 table?
谢谢!
如果您不想在 bar
中存储 foo
的密钥,那么您必须建立多对多关系。使它表现得像一对多关系的方式取决于您之后的实现,仍然有一种方法可以确保 bar
只有一个 foo
,但是对于 EF6 来说,要使结点 table,唯一的办法就是多对多关系。
很抱歉恢复这个线程,但我想分享我创建的一个实用程序来处理具有许多此类关系实例的 WebApi。我们有多个业务对象,每个业务对象都与 EventHistory、消息、文件等有关系,跟踪所有 FluentAPI 函数很麻烦。这是我想出的:
/// <summary>
/// Maps a many-to-many relationship that can only be navigated from TSource to TTarget.
/// </summary>
/// <typeparam name="TSource">Source type that can navigate to TTarget.</typeparam>
/// <typeparam name="TTarget">Target type that has no direct link back to TSource.</typeparam>
/// <param name="modelBuilder">An instance of DbModelBuilder</param>
/// <param name="expr">Lambda expression specifying the navigation property for this relationship from TSource to TTarget.</param>
/// <param name="leftKey">Optional argument to override the foreign key to TSource</param>
/// <param name="rightKey">Optional argument to override the foreign key to TTarget</param>
public static void MapDirectionalManyToMany<TSource, TTarget>(DbModelBuilder modelBuilder, Expression<Func<TSource, ICollection<TTarget>>> expr, string tableName = null, string leftKey = null, string rightKey = null)
where TSource : class
where TTarget : class {
modelBuilder.Entity<TSource>()
.HasMany(expr)
.WithMany()
.Map(m => {
m.MapLeftKey(leftKey ?? typeof(TSource).Name + "Id");
m.MapRightKey(rightKey ?? typeof(TTarget).Name + "Id");
m.ToTable(tableName ?? typeof(TSource).Name + typeof(TTarget).Name);
});
}
我这样应用关系:
ModelUtils.MapDirectionalManyToMany<MyResourceModel, SharedHistoryModel>(modelBuilder, x => x.History);
ModelUtils.MapDirectionalManyToMany<OtherResourceModel, SharedHistoryModel>(modelBuilder, x => x.History, "renamed_history");
我首先使用 EF6 代码创建数据库,然后努力使用联结创建一对多关系 table。
这是我正在尝试做的一个例子:
Foo
个实体可以包含任意数量 (0-n) 个 Bar
个实体,但是 Bar
个实体不一定属于 Foo
个。我可能希望不同类型的实体也包含一个或多个 Bar
,因此 Bar
不包含其父项的外键很重要。
所以连接 table 会像这样:
Name | FooBar
------------|-------
Primary Key | BarID
Key | FooID
因此,如果我们按如下方式创建实体:
public class Foo
{
public long ID { get; set; }
public ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public long ID { get; set; }
}
然后配置它们:
public class FooConfiguration : EntityTypeConfiguration<Foo>
{
HasKey(p => p.ID);
HasMany(p => p.Bars)
.WithRequired()
.Map(m => {
m.ToTable("FooBar");
m.MapKey("FooKey");
});
}
但这会导致抛出以下异常:
An exception of type 'System.InvalidOperationException' occurred in mscorlib.dll but was not handled in user code. Additional information: The specified table 'FooBar' was not found in the model. Ensure that the table name has been correctly specified.
不幸的是,我不确定这意味着什么 - 我需要创建一个单独的 FooBar
实体吗?
如何配置这些实体以便正确创建连接 table?
谢谢!
如果您不想在 bar
中存储 foo
的密钥,那么您必须建立多对多关系。使它表现得像一对多关系的方式取决于您之后的实现,仍然有一种方法可以确保 bar
只有一个 foo
,但是对于 EF6 来说,要使结点 table,唯一的办法就是多对多关系。
很抱歉恢复这个线程,但我想分享我创建的一个实用程序来处理具有许多此类关系实例的 WebApi。我们有多个业务对象,每个业务对象都与 EventHistory、消息、文件等有关系,跟踪所有 FluentAPI 函数很麻烦。这是我想出的:
/// <summary>
/// Maps a many-to-many relationship that can only be navigated from TSource to TTarget.
/// </summary>
/// <typeparam name="TSource">Source type that can navigate to TTarget.</typeparam>
/// <typeparam name="TTarget">Target type that has no direct link back to TSource.</typeparam>
/// <param name="modelBuilder">An instance of DbModelBuilder</param>
/// <param name="expr">Lambda expression specifying the navigation property for this relationship from TSource to TTarget.</param>
/// <param name="leftKey">Optional argument to override the foreign key to TSource</param>
/// <param name="rightKey">Optional argument to override the foreign key to TTarget</param>
public static void MapDirectionalManyToMany<TSource, TTarget>(DbModelBuilder modelBuilder, Expression<Func<TSource, ICollection<TTarget>>> expr, string tableName = null, string leftKey = null, string rightKey = null)
where TSource : class
where TTarget : class {
modelBuilder.Entity<TSource>()
.HasMany(expr)
.WithMany()
.Map(m => {
m.MapLeftKey(leftKey ?? typeof(TSource).Name + "Id");
m.MapRightKey(rightKey ?? typeof(TTarget).Name + "Id");
m.ToTable(tableName ?? typeof(TSource).Name + typeof(TTarget).Name);
});
}
我这样应用关系:
ModelUtils.MapDirectionalManyToMany<MyResourceModel, SharedHistoryModel>(modelBuilder, x => x.History);
ModelUtils.MapDirectionalManyToMany<OtherResourceModel, SharedHistoryModel>(modelBuilder, x => x.History, "renamed_history");