2017-05-22 37 views
1

我对EF非常不熟悉,而且我一直在努力解决我相信是相当平凡的问题。 我有两个表,SpecialCondition和SpecialConditionDepartment。特殊条件可以应用于多个部门,因此在SpecialConditionDepartment表中我存储了conditionID和deparmentID。如果条件适用于两个部门,则SpecialConditionDepartment表中将有两行具有相同的conditionID。当更新存储库中的现有对象时,EF'无法在对象中插入重复键'

public class SpecialCondition 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<SpecialConditionDepartment> Departments { get; set; } 
} 

public class SpecialConditionDepartment 
{ 
    private SpecialConditionDepartment() 
    { 
    } 

    public SpecialConditionDepartment(int conditionID, int departmentID) 
    { 
     ConditionID = conditionID; 
     DepartmentID = departmentID; 
    } 

    public int ConditionID { get; set; } 
    public int DepartmentID { get; set; } 
} 


var specialCondition =modelBuilder.Entity<SpecialCondition>().ToTable("SpecialCondition"); 
     specialCondition.HasMany(o => o.Departments) 
      .WithOptional() 
      .HasForeignKey(c => c.ConditionID); 

     modelBuilder.Entity<SpecialConditionDepartment>().ToTable("SpecialConditionDepartment") 
      .HasKey(c => new { c.ConditionID, c.DepartmentID }); 

最后,Web服务中的更新方法非常简单。我抓住从DB对象,更新名称和部门列表,然后使用通用库更新()更新:

public SpecialConditionDto UpdateCondition(SpecialConditionDto dto) 
{ 
     SpecialCondition specialcondition = specialConditionRepository.GetById(dto.ID); 

     specialcondition.Name = dto.Name; 
     specialcondition.Departments = 
      mapper.Map<ICollection<SpecialConditionDepartmentDto>, ICollection<SpecialConditionDepartment>>(
       dto.Departments); 
     specialConditionRepository.Update(specialcondition); 
     unitOfWork.Commit(); 
     return specialcondition.Map<SpecialConditionDto>(); 
} 

的SpecialConditionRepository从RepositoryBase,这反过来从IRepository

public class SpecialConditionRepository : RepositoryBase<SpecialCondition>, ISpecialConditionRepository 
public abstract class RepositoryBase<T> : IRepository<T> where T : class 
继承继承

和知识库的基础,所有的通用添加,GetById,更新等被定义

public abstract class RepositoryBase<T> : IRepository<T> where T : class 
{ 
    protected IDbSet<T> Set 
    { 
    get { return Context.Set<T>(); } 
    } 

    protected RepositoryBase() 
    { 
    DatabaseFactory = new DatabaseFactory(); 
    } 
    private EFContext _context; 
    public EFContext Context 
    { 
    get { return _context ?? (Context = DatabaseFactory.Create()); } 
    set { _context = value; } 
    } 
} 

在上下文是模型和ID篮网已定义

public IDbSet<SpecialCondition> SpecialConditions { get; set; } 
public IDbSet<SpecialConditionDepartment> SpecialConditionDepartments { get; set; } 

相同的代码适用于创建特殊条件。当尝试更新时,它不明白我希望它更新部门,它会尝试向SpecialConditionDepartment表中添加新行,最终导致我的代码崩溃。

我缺少什么?

+0

您错过了'GetById'返回的部分。我的头顶是我的猜测是你的'DepartmentId'没有被填充。这引发了一个插入程序。这与已经存在的独特约束相冲突。我只是设置一个断点,并观察对象的“特殊条件”具有适当的属性。 – djangojazz

+0

为清晰起见进行了编辑。我从数据库中获取对象,然后更新名称和Departments列表。部门清单上的值(ConditionID和DepartmentID)是有效的。问题是,当我更新适用于部门6的ID 13的条件时,它会尝试将行ConditionID = 13 DepartmentID 6添加到SpecialConditionDepartment表中,但它不明白该行已经存在于此之前 – Ritx

+0

好吧,我已关闭不管怎么说,我在看你的桌子下面的物品时,我所说的关键。您是直接从您的repo类显示的代码?因为什么是'specialConditionRepository'对象?通常在EF中,你会像(var context = new MyEFContext())那样创建一个“上下文”,然后在那里工作。您将更新和提交混合为两个不同的对象。但是你说它适用于插入,所以我很好奇,因为它可能没有被提交,但第一次插入时出现,然后在第二次插入时出现。 – djangojazz

回答

0

好了,开始我认为我们应该保持这种简单,只是在一个数据库中定义的两个表:

tdCountry has a CountryId(int, PrimaryKey), CountryName(varchar(128)) 
tePerson has a PersonId(int), FirstName(varchar(128), LastName(varchar(128)), CountryId(int, ForeignKey to tdCountry(CountryId)) 

我定义EF这些关系,像这样。我把我的EF容器名称“TesterEntities”以供参考。(文所示)

public partial class tdCountry 
{ 
    public tdCountry() 
    { 
     this.tePerson = new HashSet<tePerson>(); 
    } 

    public int CountryId { get; set; } 
    public string CountryName { get; set; } 

    public virtual ICollection<tePerson> tePerson { get; set; } 
} 

public partial class tePerson 
{ 
    public int PersonId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public Nullable<int> CountryId { get; set; } 

    public virtual tdCountry tdCountry { get; set; } 
} 

现在你在做什么,是从出现单个项目一次更改多个项目。我对您的回购并不熟悉,但它似乎无论如何,都是过分的,可能会导致比解决方案更多的问题。通常情况下,如果我有一个国家可以有很多人的一对多关系。我可能希望通过执行插入操作进行更新,然后说:“嘿,更新全部或部分到现在的位置。”我可以在上下文中用EF中的几行代码来实现这一点。像这样:

static void Main(string[] args) 
{ 
    //This could be an add in a repo 
    using (var context = new TesterEntities()) 
    { 
    context.tdCountry.Add(new tdCountry { CountryName = "Canada" }); 
    context.SaveChanges(); 
    } 

    //This could be an update in a repo 
    using (var context = new TesterEntities()) 
    { 
    var getNewCountry = context.tdCountry.SingleOrDefault(x => x.CountryName == "Canada"); 
    var people = context.tePerson.ToList(); 
    getNewCountry.tePerson = people; 
    context.SaveChanges(); 
    } 
} 

我不能肯定,但我知道,我一般平时走路就工作单位的线被包裹在一个方面,然后有这方面暴露出来。这是通过使用声明完成的,然后处理它。我也做我的工作,然后通常引用上下文的'SaveChanges()',并避免在重命名事件的回购中包装太多。我已经在他们反复重新命名的地方工作过,EF正在这样做,恕我直言,它增加了复杂性,不需要任何东西。第二种方法是真正做你需要的。基本上我得到了我刚刚创建的对象。然后我得到我需要更新的对象的列表。然后,我将这个对象引用到与这个上下文相关的内存中,并将它的属性赋值给我想要的。然后我再次将上下文告诉SaveChanges(),并理解如何运行更新。

如果您有问题,可能是因为您有参考文献试图更新太多东西,而不是不够,而且您的对象处于独立状态。如果你的关系不正确,你也可能会有问题。通常情况下,如果您正在进行典型的显示,您有'* .edmx'文件,则可以观察这些关系。

我会尝试摆脱该回购,直到您可以验证控制台应用程序或更小功能中的工作代码。有时候,它有助于退后一步,从头开始重构,而不是处理许多您可能会或可能不知道为什么他们以某种方式完成的作品。

+0

非常感谢您的建议。我会试试这种方法,看看我能否实现它! – Ritx

相关问题