【问题标题】:Entity Framework is Inserting entity when defining a many-to-many relationship实体框架在定义多对多关系时正在插入实体
【发布时间】:2016-03-14 06:38:31
【问题描述】:

我正在尝试使用 Entity Framework (v6.0) 中的两个现有实体在 CountriesRegions 之间创建多对多关系(一个国家可能属于到许多地区,一个地区包含许多国家)。它不是简单地将 CountryIDRegionID 添加到连接表,而是尝试将新的 Country 记录添加到 countries 表,当然会导致主键发生冲突错误,因为它尝试将 Country 添加到表中,即使它已经存在。 ...这是代码...

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);
    }
}

最后是引发错误的代码...我使用相同的上下文来检索对 CountryRegion 记录的引用,因此不应该存在交叉上下文问题,我也使用 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.

当然,我并没有尝试在“国家/地区”表中插入记录,但所有映射似乎都是正确的,所以我不清楚它为什么要这样做。

我已经多次看到这个问题发布了,但很多都没有得到答复,并且发布的答案(我已经看到)对我不起作用。发布的大多数问题都已通过将模型附加到上下文中得到解决……但这对我来说应该不是问题,因为我使用的是单个上下文并使用已附加/跟踪的实体。

有什么想法... ??谢谢你的帮助...

我尝试过的一些建议...

// 
// 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();

【问题讨论】:

    标签: c# entity-framework many-to-many


    【解决方案1】:

    我发现了问题所在......尽管有很多相反的例子......我在 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 实现。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-28
      • 2011-12-17
      相关资源
      最近更新 更多