实体框架-创建父实体

时间:2018-10-08 19:53:12

标签: c# entity-framework

我收到以下错误

  

“附加类型为'Datos.Medico'的实体失败,因为相同类型的另一个实体已经具有相同的主键值。使用'Attach'方法或将实体的状态设置为'Unchanged'时,可能会发生这种情况。 '或'Modified'(如果图形中的任何实体具有冲突的键值),这可能是因为某些实体是新的并且尚未接收到数据库生成的键值。在这种情况下,请使用'Add'方法或'Added'实体状态以跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。”

当我尝试将实体附加到上下文时,发生错误,如下所示:

public override void Alta(Medico medico)
{
    foreach (Especialidad especialidad in medico.Especialidad)
    {
        this.context.Especialidad.Attach(especialidad);
    }
    base.Alta(medico);
}

获取Especialidad实体是为了跟踪,因为它用于填充组合:

public List<Especialidad> ObtenerEspecialidades()
{
    var especialidades = context.Especialidad.AsNoTracking();
    /*
    var especialidades = from unaEspecialidad in context.Especialidad
                         select unaEspecialidad;
                         */

    return especialidades.ToList();
}

然后从组合中取出并添加到Medico实体中,该实体包含一个List<Especialidad>

谢谢。

更新

我根据要求包含了Entities定义:

    public Medico()
    {
        this.Agenda = new HashSet<Agenda>();
        this.Historia_Clinica_Elemento = new HashSet<HistoriaClinicaElemento>();
        this.Turno = new HashSet<Turno>();
        this.Especialidad = new HashSet<Especialidad>();
        this.Espera_Atencion = new HashSet<EsperaAtencion>();
    }

    public int ID { get; set; }
    public string Nombre { get; set; }
    public string Apellido { get; set; }
    public Nullable<int> Matricula { get; set; }
    public Nullable<int> TipoDocumento { get; set; }
    public Nullable<long> Numero_Documento { get; set; }
    public Nullable<System.DateTime> Fecha_Nacimiento { get; set; }
    public Nullable<int> Direccion { get; set; }
    public string Usuario { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Agenda> Agenda { get; set; }
    public virtual Direccion Direccion1 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<HistoriaClinicaElemento> Historia_Clinica_Elemento { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Turno> Turno { get; set; }
    public virtual TipoDocumento Tipo_Documento { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Especialidad> Especialidad { get; set; }
    public virtual Usuario Usuario1 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<EsperaAtencion> Espera_Atencion { get; set; }

特殊:

public partial class Especialidad
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Especialidad()
    {
        this.Medico = new HashSet<Medico>();
    }

    public int ID { get; set; }
    public string Nombre { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Medico> Medico { get; set; }
}

1 个答案:

答案 0 :(得分:0)

取决于您的DbContext保持打开状态的时间,它可以已经与实体关联。例如,如果您要遍历一组Medico,并且两个具有相同的Espacialidad,则第一个将附加,而第二个将引发错误。

在将实体附加到DbContext之前,应始终检查该实体是否已附加:

foreach (Especialidad especialidad in medico.Especialidad)
{
     if (!this.context.Especialidad.Local.Any(x => x == especialidad))        
         this.context.Especialidad.Attach(especialidad);
}

编辑:适用于许多没有双向引用的情况。

从Especialidad移除Medico系列

您目前在哪里将医生映射为以下位置:

HasMany(x => x.Especialidad)
    .WithMany(x => x.Medico)
    .Map(x => 
    { 
       x.ToTable("Medico_Especialidad");
       x.MapLeftKey("MedicoID");
       x.MapRightKey("EspecialidadID");
    });

...这将变为:

HasMany(x => x.Especialidad)
    .WithMany() // Note the empty return reference.
    .Map(x => 
    { 
       x.ToTable("Medico_Especialidad");
       x.MapLeftKey("MedicoID");
       x.MapRightKey("EspecialidadID");
    });

您可能需要使用Especialidad的专业来获取医生的任何代码.Medico将需要更改以从Doctor一方解决,即

代替:

var medicos = context.Especialidad.Find(especialidadID).Medico

看起来像:

var medicos = context.Medico.Where(x => x.Especialidad.Any(e => e.ID == especialidadID)).ToList();

当涉及多对多或多对一关系时,为使代码更简单并避免引用混淆,通常建议避免双向引用,除非绝对需要它们。双向引用带来的部分麻烦是,当A引用B且B引用A时,您需要确保上下文能够在两边解析出完全相同的A和B。将实体分离并重新附加到上下文时,这将导致关联错误或重复的PK插入错误。