我正在尝试使用实体框架(v6.0)中的两个现有实体创建多对多关系国家/地区和地区(一个国家/地区可能属于许多地区和一个地区包含许多国家)。不是简单地将 CountryID 和 RegionID 添加到联接表中,而是尝试将新的国家/地区记录添加到国家/地区表,当然,在主键的冲突错误中,因为它尝试将国家/地区添加到表中,即使它已经存在。 ......这里是代码......
SQL Server表定义......
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);
}
}
最后抛出错误的代码......我使用相同的上下文来检索对国家和区域记录的引用,所以不应该有一个交叉上下文问题,我也使用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.
当然,我并没有试图将记录插入&#34;国家&#34;表,但所有映射似乎都是正确的,所以我不清楚它为什么要这样做。
我已经看过这个问题多次发布但很多都没有得到答复,而且发布的答案(我已经看过)对我没有用。发布的大多数问题都是通过将模型附加到上下文来解决的......但是,这对我来说应该不是问题,因为我使用单个上下文并使用已经附加/跟踪的实体。
有什么想法......?谢谢你的帮助......
我尝试过的一些建议......
//
// 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();
答案 0 :(得分:0)
我弄清楚了问题是什么......尽管有许多相反的例子......我在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实现。< / p>