Entity Framework 是在定义多对多关系时插入实体
Entity Framework is Inserting entity when defining a many-to-many relationship
我正在尝试在 Countries 和 之间使用 Entity Framework (v6.0) 中的两个现有实体创建多对多关系Regions(一个国家可能属于多个地区,一个地区又包含多个国家)。而不是简单地将 CountryID 和 RegionID 添加到连接 table 但是它试图添加一个新的 Country 记录到 countries table,当然会导致主键在尝试添加 Country[= 时出现冲突错误46=] 到 table,即使它已经存在。 ...这是代码...
SQL 服务器 Table 定义 ...
CREATE TABLE [contact].[countries]
(
[country_id] BIGINT NOT NULL PRIMARY KEY IDENTITY,
[country_name] NVARCHAR(255) NOT NULL,
[country_code] NVARCHAR(50) NULL,
[country_capital] NVARCHAR(255) NULL
)
CREATE TABLE [contact].[regions]
(
[region_id] BIGINT NOT NULL PRIMARY KEY IDENTITY,
[region_name] NVARCHAR(255) NOT NULL,
[region_desc] NVARCHAR(MAX) NULL,
[region_category] NVARCHAR(255) NULL,
[created_by] NVARCHAR(50) NOT NULL,
[created_date] DATETIME NOT NULL,
[updated_by] NVARCHAR(50) NOT NULL,
[updated_date] DATETIME NOT NULL
)
CREATE TABLE [contact].[country_regions]
(
[country_id] BIGINT NOT NULL ,
[region_id] BIGINT NOT NULL,
PRIMARY KEY ([region_id], [country_id]),
[created_by] NVARCHAR(50) NOT NULL,
[created_date] DATETIME NOT NULL,
[updated_by] NVARCHAR(50) NOT NULL,
[updated_date] DATETIME NOT NULL
CONSTRAINT [FK_CountryRegions_ToCountries] FOREIGN KEY ([country_id]) REFERENCES [contact].[countries]([country_id]) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT [FK_CountryRegions_ToRegion] FOREIGN KEY ([region_id]) REFERENCES [contact].[regions]([region_id]) ON UPDATE CASCADE ON DELETE CASCADE
)
这是模型定义...
public class Country : BaseTimestampableModel
{
public String Name { get; set; }
public String Code { get; set; }
public String Capital { get; set; }
public virtual ICollection<State> States { get; set; }
public virtual ICollection<Region> Regions { get; set; }
}
public class Region : BaseTimestampableModel
{
public String Name { get; set; }
public String Description { get; set; }
public String Category { get; set; }
public virtual ICollection<State> States { get; set; }
public virtual ICollection<Country> Countries { get; set; }
}
Code-First 映射代码...
internal static void Map(ref DbModelBuilder modelBuilder)
{
var entityMap = modelBuilder.Entity<Country>();
entityMap.ToTable("countries", schemaName: "contact");
#region map columns
entityMap
.HasKey(e => e.ID)
.Property(e => e.ID)
.HasColumnName("country_id")
.HasColumnType("bigint")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
entityMap
.Property(e => e.Name)
.HasColumnName("country_name")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsRequired();
entityMap
.Property(e => e.Code)
.HasColumnName("country_code")
.HasColumnType("nvarchar")
.HasMaxLength(50)
.IsOptional();
entityMap
.Property(e => e.Capital)
.HasColumnName("country_capital")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsOptional();
#endregion map columns
#region navigation props
entityMap
.HasMany(e => e.States)
.WithOptional(s=>s.Country);
#endregion navigation props
TimestampableModelMapper.Map<Country>(ref modelBuilder);
}
}
public class RegionMapper
{
internal static void Map(ref DbModelBuilder modelBuilder)
{
var entityMap = modelBuilder.Entity<Region>();
entityMap.ToTable("regions", schemaName: "contact");
#region map columns
entityMap
.HasKey(e => e.ID)
.Property(e => e.ID)
.HasColumnName("region_id")
.HasColumnType("bigint")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
entityMap
.Property(e => e.Name)
.HasColumnName("region_name")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsRequired();
entityMap
.Property(e => e.Description)
.HasColumnName("region_desc")
.HasColumnType("nvarchar")
.IsMaxLength()
.IsOptional();
entityMap
.Property(e => e.Category)
.HasColumnName("region_category")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsOptional();
#endregion map columns
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("country_id");
cr.MapRightKey("region_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("state_id");
sr.MapRightKey("region_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
TimestampableModelMapper.Map<Region>(ref modelBuilder);
}
}
最后是抛出错误的代码...我使用相同的上下文检索对 Country 和 Region 记录的引用所以不应该有跨上下文问题,我也使用 ID 检索它们,而不是传递模型以避免附加和分离实体的问题;检索到的实例已被上下文跟踪。
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
region.Countries.Add(country);
DbContext.SaveChanges();
这一切都以错误告终...
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_CountryRegions_ToCountries".
The conflict occurred in database "DataBaseName", table "contact.countries", column 'country_id'.
The statement has been terminated.
当然,我并没有尝试将记录插入 "Countries" table,但是所有的映射似乎都是正确的,所以我不清楚为什么要这样做。
我已经看到这个问题发布了好几次,但很多都没有得到解答,而且发布的答案(我看到的)对我没有用。发布的大多数问题都已通过将模型附加回上下文得到解决......然而,这对我来说应该不是问题,因为我使用的是单个上下文并且已经使用 attached/tracked 个实体。
有什么想法……??感谢您的帮助...
我试过的一些建议...
//
// set the state to unchanged ...
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
uow.DbContext.Entry<Country>(country).State = System.Data.Entity.EntityState.Unchanged;
region.Countries.Add(country);
DbContext.SaveChanges();
//
// Add region to the country rather than country to the region
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
country.Regions.Add(region);
DbContext.SaveChanges();
我弄清楚了问题所在...尽管有很多相反的例子...我在 RegionMapper 中反向映射了多对多关系。
原来是这样……
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("country_id");
cr.MapRightKey("region_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("state_id");
sr.MapRightKey("region_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
简单地切换左右键就可以了...
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("region_id");
cr.MapRightKey("country_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("region_id");
sr.MapRightKey("state_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
我没有详细阅读所有内容,但 this post 建议可能在 EF5 中更改了顺序,这是有道理的,因为我最初查看的大多数示例都来自 EF4 实现。
我正在尝试在 Countries 和 之间使用 Entity Framework (v6.0) 中的两个现有实体创建多对多关系Regions(一个国家可能属于多个地区,一个地区又包含多个国家)。而不是简单地将 CountryID 和 RegionID 添加到连接 table 但是它试图添加一个新的 Country 记录到 countries table,当然会导致主键在尝试添加 Country[= 时出现冲突错误46=] 到 table,即使它已经存在。 ...这是代码...
SQL 服务器 Table 定义 ...
CREATE TABLE [contact].[countries]
(
[country_id] BIGINT NOT NULL PRIMARY KEY IDENTITY,
[country_name] NVARCHAR(255) NOT NULL,
[country_code] NVARCHAR(50) NULL,
[country_capital] NVARCHAR(255) NULL
)
CREATE TABLE [contact].[regions]
(
[region_id] BIGINT NOT NULL PRIMARY KEY IDENTITY,
[region_name] NVARCHAR(255) NOT NULL,
[region_desc] NVARCHAR(MAX) NULL,
[region_category] NVARCHAR(255) NULL,
[created_by] NVARCHAR(50) NOT NULL,
[created_date] DATETIME NOT NULL,
[updated_by] NVARCHAR(50) NOT NULL,
[updated_date] DATETIME NOT NULL
)
CREATE TABLE [contact].[country_regions]
(
[country_id] BIGINT NOT NULL ,
[region_id] BIGINT NOT NULL,
PRIMARY KEY ([region_id], [country_id]),
[created_by] NVARCHAR(50) NOT NULL,
[created_date] DATETIME NOT NULL,
[updated_by] NVARCHAR(50) NOT NULL,
[updated_date] DATETIME NOT NULL
CONSTRAINT [FK_CountryRegions_ToCountries] FOREIGN KEY ([country_id]) REFERENCES [contact].[countries]([country_id]) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT [FK_CountryRegions_ToRegion] FOREIGN KEY ([region_id]) REFERENCES [contact].[regions]([region_id]) ON UPDATE CASCADE ON DELETE CASCADE
)
这是模型定义...
public class Country : BaseTimestampableModel
{
public String Name { get; set; }
public String Code { get; set; }
public String Capital { get; set; }
public virtual ICollection<State> States { get; set; }
public virtual ICollection<Region> Regions { get; set; }
}
public class Region : BaseTimestampableModel
{
public String Name { get; set; }
public String Description { get; set; }
public String Category { get; set; }
public virtual ICollection<State> States { get; set; }
public virtual ICollection<Country> Countries { get; set; }
}
Code-First 映射代码...
internal static void Map(ref DbModelBuilder modelBuilder)
{
var entityMap = modelBuilder.Entity<Country>();
entityMap.ToTable("countries", schemaName: "contact");
#region map columns
entityMap
.HasKey(e => e.ID)
.Property(e => e.ID)
.HasColumnName("country_id")
.HasColumnType("bigint")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
entityMap
.Property(e => e.Name)
.HasColumnName("country_name")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsRequired();
entityMap
.Property(e => e.Code)
.HasColumnName("country_code")
.HasColumnType("nvarchar")
.HasMaxLength(50)
.IsOptional();
entityMap
.Property(e => e.Capital)
.HasColumnName("country_capital")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsOptional();
#endregion map columns
#region navigation props
entityMap
.HasMany(e => e.States)
.WithOptional(s=>s.Country);
#endregion navigation props
TimestampableModelMapper.Map<Country>(ref modelBuilder);
}
}
public class RegionMapper
{
internal static void Map(ref DbModelBuilder modelBuilder)
{
var entityMap = modelBuilder.Entity<Region>();
entityMap.ToTable("regions", schemaName: "contact");
#region map columns
entityMap
.HasKey(e => e.ID)
.Property(e => e.ID)
.HasColumnName("region_id")
.HasColumnType("bigint")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
.IsRequired();
entityMap
.Property(e => e.Name)
.HasColumnName("region_name")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsRequired();
entityMap
.Property(e => e.Description)
.HasColumnName("region_desc")
.HasColumnType("nvarchar")
.IsMaxLength()
.IsOptional();
entityMap
.Property(e => e.Category)
.HasColumnName("region_category")
.HasColumnType("nvarchar")
.HasMaxLength(255)
.IsOptional();
#endregion map columns
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("country_id");
cr.MapRightKey("region_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("state_id");
sr.MapRightKey("region_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
TimestampableModelMapper.Map<Region>(ref modelBuilder);
}
}
最后是抛出错误的代码...我使用相同的上下文检索对 Country 和 Region 记录的引用所以不应该有跨上下文问题,我也使用 ID 检索它们,而不是传递模型以避免附加和分离实体的问题;检索到的实例已被上下文跟踪。
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
region.Countries.Add(country);
DbContext.SaveChanges();
这一切都以错误告终...
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_CountryRegions_ToCountries".
The conflict occurred in database "DataBaseName", table "contact.countries", column 'country_id'.
The statement has been terminated.
当然,我并没有尝试将记录插入 "Countries" table,但是所有的映射似乎都是正确的,所以我不清楚为什么要这样做。
我已经看到这个问题发布了好几次,但很多都没有得到解答,而且发布的答案(我看到的)对我没有用。发布的大多数问题都已通过将模型附加回上下文得到解决......然而,这对我来说应该不是问题,因为我使用的是单个上下文并且已经使用 attached/tracked 个实体。
有什么想法……??感谢您的帮助...
我试过的一些建议...
//
// set the state to unchanged ...
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
uow.DbContext.Entry<Country>(country).State = System.Data.Entity.EntityState.Unchanged;
region.Countries.Add(country);
DbContext.SaveChanges();
//
// Add region to the country rather than country to the region
Region region = DbContext.Regions.Where(e => e.ID == regionID).SingleOrDefault();
Country country = DbContext.Countries.Where(e => e.ID == countryID).SingleOrDefault();
country.Regions.Add(region);
DbContext.SaveChanges();
我弄清楚了问题所在...尽管有很多相反的例子...我在 RegionMapper 中反向映射了多对多关系。
原来是这样……
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("country_id");
cr.MapRightKey("region_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("state_id");
sr.MapRightKey("region_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
简单地切换左右键就可以了...
#region navigation props
entityMap
.HasMany(r => r.Countries)
.WithMany(c => c.Regions)
.Map(cr =>
{
cr.MapLeftKey("region_id");
cr.MapRightKey("country_id");
cr.ToTable("country_regions", schemaName: "contact");
});
entityMap
.HasMany(r => r.States)
.WithMany(s => s.Regions)
.Map(sr =>
{
sr.MapLeftKey("region_id");
sr.MapRightKey("state_id");
sr.ToTable("state_regions", schemaName:"contact");
});
#endregion navigation props
我没有详细阅读所有内容,但 this post 建议可能在 EF5 中更改了顺序,这是有道理的,因为我最初查看的大多数示例都来自 EF4 实现。