实体框架是在定义多对多关系时插入实体

时间:2016-03-13 15:26:16

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

我正在尝试使用实体框架(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();

1 个答案:

答案 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>