无法保存与相关的实体

时间:2017-05-15 10:12:20

标签: c# sql-server-2008 entity-framework-6

假设我有这种情况。

这是我的表(ParentID列包含LocationID的值):

示例:

            LocationID        LocationCode        ParentID
Row 1           1              Code_Parent          NULL
Row 2           2              Code_Child            1 //ID of row 1

结构:

CREATE TABLE [dbo].[Location]
(
    [LocationID] [int] IDENTITY(1,1) NOT NULL,
    [ParentID] [int] NULL,
    [LocationCode] [varchar](20) NOT NULL,
    [LocationName] [nvarchar](125) NULL,

    CONSTRAINT [PK_Location_LocationID] 
        PRIMARY KEY CLUSTERED ([LocationID] ASC)
)

ALTER TABLE [dbo].[Location] WITH CHECK 
    ADD CONSTRAINT [FK_Location_Location_ParentID] 
    FOREIGN KEY([ParentID]) REFERENCES [dbo].[Location] ([LocationID])
GO

ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [FK_Location_Location_ParentID]
GO

Entity Framework 6.0:

EF是从PowerTool生成的,以下是类:

public LocationMap()
{
    // Primary Key
    this.HasKey(t => t.LocationID);

    // Properties
    this.Property(t => t.LocationCode)
                .IsRequired()
                .HasMaxLength(20);

    this.Property(t => t.LocationName)
                .HasMaxLength(125);

    // Table & Column Mappings
    this.ToTable("Location");
    this.Property(t => t.LocationID).HasColumnName("LocationID");
    this.Property(t => t.ParentID).HasColumnName("ParentID");
    this.Property(t => t.LocationCode).HasColumnName("LocationCode");
    this.Property(t => t.LocationName).HasColumnName("LocationName");

    // Relationships
    this.HasOptional(t => t.Location2)
                .WithMany(t => t.Location1)
                .HasForeignKey(d => d.ParentID);
}

实现:

  • MD_Location1是儿童列表
  • MD_Location2是父位置

代码:

IUnitOfWorkAsync _unitOfWorkAsync = new UnitOfWork(dataContext); //it worked

// 1. add parent location
MD_Location locParent = new MD_Location()
        {
            ParentID = null,
            LocationName = "Parent 1",
            ObjectState = ObjectState.Added
        };

// 2. add 2 child locations
MD_Location locChild1 = new MD_Location()
        {
            ParentID = locParent.LocationID,     // is code right?
            LocationName = "Child 1",
            ObjectState = ObjectState.Added
        };

locChild1.MD_Location2 = locParent;      // I tried but it does not work
locParent.MD_Location1.Add(locChild1);   // I also tried but it not work either

MD_Location locChild2 = new MD_Location()
        {
            ParentID = locParent.LocationID,   // is code right?
            LocationName = "Child 2",
            ObjectState = ObjectState.Added
        };

locChild2.MD_Location2 = locParent;     // I tried but it does not work
locParent.MD_Location1.Add(locChild2);  // I also tried but it not work either

_unitOfWorkAsync.Repository<MD_Location>().Insert(location);
_unitOfWorkAsync.SaveChanges();

但是会发生错误:

  

附加“位置”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。

我怎么能解决这个问题?

请告知。

非常感谢。

2 个答案:

答案 0 :(得分:1)

在将该对象保存到数据库之前从locParent.LocationID分配parrentId并且如果您在该列上启用了标识,那么LocationId属性将保持值0并且EF不知道ParentId需要从auto附加生成了locParent对象的Id。

    MD_Location locChild2 = new MD_Location()
    {
        //ParentID = locParent.LocationID, //is not correct
        LocationName = "Child 2",
        ObjectState = ObjectState.Added
    };

相反,您应该使用导航属性,以便EF可以理解需要首先保存locParent对象,并且需要将其自动生成的Id保存在locChild2的ParentId列中。

    MD_Location locChild2 = new MD_Location()
    {
        MD_Location2 = locParent,
        LocationName = "Child 2",
        ObjectState = ObjectState.Added
    };

答案 1 :(得分:1)

这是一种没有任何噪音的简化工作解决方案:

模型定义:

public class Model1 : DbContext
{
    public Model1()
        : base( "name=Model1" )
    {
    }

    protected override void OnModelCreating( DbModelBuilder modelBuilder )
    {
        base.OnModelCreating( modelBuilder );

        var location = modelBuilder.Entity<Location>();

        // location.ToTable( nameof( Location ) );
        location.HasKey( e => e.Id );
        location.Property( e => e.Code )
            .IsRequired()
            .HasMaxLength( 20 );
        location.Property( e => e.Name )
            .HasMaxLength( 125 );
        location.HasOptional( e => e.Parent )
            .WithMany( e => e.Children )
            .HasForeignKey( e => e.ParentId )
            .WillCascadeOnDelete( false );
    }

    public virtual DbSet<Location> Locations { get; set; }
}

public class Location
{
    public int Id { get; set; }

    public string Code { get; set; }
    public string Name { get; set; }

    public int? ParentId { get; set; }
    public virtual Location Parent { get; set; }
    public virtual ICollection<Location> Children { get; set; }
}

用例

using ( var db = new Model1() )
{
    var parent_location = new Location
    {
        Code = "Code_Parent",
    };

    var child_location = new Location
    {
        Code = "Code_Child",
        Parent = parent_location,
    };

    db.Locations.Add( child_location );
    db.SaveChanges();
}

主要区别在于,我将实例附加到导航属性(Parent = parent_location),EF将执行其余操作,并且还会处理我未明确添加到位置集合的父位置。