c# - EntityCollection - ICollection<InterfaceTEntity> - 运行时问题/怪癖

标签 c# entity-framework interface entity-framework-6 t4

背景信息

我正在使用数据库优先方法。

我创建了一个从 EDMX 文件生成接口(interface)的 TextTemplate (.tt) 文件,此外,我修改了 EDMX 文件(项目项)包含/生成的原始 TextTemplate 文件,使生成的类实现这些接口(interface)。

[人](部分公开类)

namespace TestSolution.Domain.Entities
{
  using System;
  using System.Collections.Generic;
  using TestSolution.Domain.Entities;

  public partial class Person : IPerson
  {
    public Person()
    {
        //this.CrewMembers = new HastSet<CrewMember>();
        this.CrewMembers = new HashSet<ICrewMember>();
    }

    public Person(IPerson iPerson)
        {
        this.PersonID = iPerson.PersonID;
        this.First = iPerson.First;
        this.Last = iPerson.Last;
        //this.CrewMembers = new HastSet<CrewMember>();
        this.CrewMembers = new HashSet<ICrewMember>();
    }
    public int PersonID { get; set; }
    public string First { get; set; }
    public string Last { get; set; }

    //public virtual ICollection<CrewMember> CrewMembers { get; set; }
    public virtual ICollection<ICrewMember> CrewMembers { get; set; }
  }
}

正如您在上面的代码示例中看到的,我还添加了一个构造函数,它采用接口(interface)来初始化 Person 类...

[IPerson](界面)

namespace TestSolution.Domain.Entities
{
    using System;
    using System.Collections.Generic;       

    public interface IPerson
    {       
         int PersonID { get; set; }
         string First { get; set; }
         string Last { get; set; }

         //ICollection<CrewMember> CrewMembers { get; set; }
         ICollection<ICrewMember> CrewMembers { get; set; }
    }
}

CrewMember类和 ICrewMember界面包含:

  • bool 属性(IsCaptainIsAssigned)
  • Int PersonID作为属性(property),Int CrewMemberID作为属性(property),
  • Person Person作为人当然。 (我也试过 IPerson Person)。

我的意图;问题

我打算使用 ICollection<ICrewMember>用于导航。然后使用实现这些接口(interface)的 DTO/模型/模型 View 对象/类。

当我生成 ICollection<InterfaceTEntity> 时类型,我没有看到任何问题.. EntityFramework.. 直到我尝试使用相同的上下文更新两个实体:context.CrewMemberscontext.People在同一个函数中。

public void UpdateCrewMemberModel(CrewMemberModel CrewMember)
    {
        var query = (from crewMember in UnitOfWork.DataContext.CrewMembers
                     where crewMember.CrewMemberID == CrewMember.CrewMemberID
                     select crewMember).First<CrewMember>();
        query.IsAssigned = CrewMember.IsAssigned;
        query.IsCaptain = CrewMember.IsCaptain;


        // Exception is thrown here 
        var queryPerson = (from person in UnitOfWork.DataContext.People
                           where person.PersonID == query.PersonID
                           select person).First<Person>();
        queryPerson.First = CrewMember.Person.First;
        queryPerson.Last = CrewMember.Person.Last;

        //Note that UnitOfWork uses a Factory Repository Pattern;
        //Commit just calls on UnitOfWork.DataContext.SaveAll() Method
        UnitOfWork.Commit();
    }

我遇到/看到的问题似乎与 EntityFramework 的更改跟踪功能有关。然而,它实际上 Root 于 EntityFramework 本身的异步操作。

如果我调试并单步执行上述方法,没有异常,并且数据库/表正确更新..

如果我在声明 queryPerson 的语句之前没有捕捉到调试点就运行它。它会抛出一个异常(关于 Person.CrewMembers 必须是 ICollection<T> 的误导性异常)..

这显然是一个时间问题


尝试的解决方法/兴趣点

我试图删除 ICollection<> 属性上的虚拟属性;没有影响问题。

我试图删除延迟加载;没有影响问题。

我试图提交查询之间的更改;不影响问题。

我试图执行使用 FirstAsync<>查询时;但我不确定我是否正确使用了它。我仍在摆弄这种方法。


*EDIT/UPDATE -(误导)异常、堆栈跟踪和目标站点

System.Data.Entity.Core.EntityException
{"The navigation property 'CrewMembers' on entity of type 'System.Data.Entity.DynamicProxies.Person_1A1EF42B1FC8D2DD0084F803201DE1DE4CF6E704C5AE129D954BD5BEAB55826C' must implement ICollection<T> in order for Entity Framework to be able to track changes in collections."}

Source: EntityFramework

at System.Data.Entity.Core.Objects.DataClasses.EntityCollection`1.CheckIfNavigationPropertyContainsEntity(IEntityWrapper wrapper)
at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Entity.Core.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedEntity, Boolean applyConstraints)
at System.Data.Entity.Core.Objects.DataClasses.EntityReference`1.set_ReferenceValue(IEntityWrapper value)
at System.Data.Entity.Core.Objects.DataClasses.EntityReference.SetEntityKey(EntityKey value, Boolean forceFixup)
at System.Data.Entity.Core.Objects.EntityEntry.FixupEntityReferenceToPrincipal(EntityReference relatedEnd, EntityKey foreignKey, Boolean setIsLoaded, Boolean replaceExistingRef)
at System.Data.Entity.Core.Objects.EntityEntry.FixupReferencesByForeignKeys(Boolean replaceAddedRefs, EntitySetBase restrictTo)
at System.Data.Entity.Core.Objects.ObjectStateManager.FixupReferencesByForeignKeys(EntityEntry newEntry, Boolean replaceAddedRefs)
at System.Data.Entity.Core.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
at lambda_method(Closure , Shaper )
at System.Data.Entity.Core.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
at System.Data.Entity.Core.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at TestSolution.Infrastructure.Service.CrewMemberService.UpdateCrewMemberModel(CrewMemberModel CrewMember) in c:\Users\brett.caswell\Documents\Visual Studio 2012\Projects\TestSolution\TestSolution.Infrastructure.Service\Services\CrewMemberServices.cs:line 67

TargetSite: {Boolean CheckIfNavigationPropertyContainsEntity(System.Data.Entity.Core.Objects.Internal.IEntityWrapper)}

*编辑/更新 - 问题

虽然问这个问题可能不正确地确定了我遇到的问题的范围...

在生成类的导航属性中将通用类型接口(interface)与 ICollection 结合使用时,我如何/如何处理 EntityFramework 内部/来自 EntityFramework 的潜在不安全线程实例(在我的 UpdateCrewmMemberModel 方法中)?

最佳答案

如果您尝试将接口(interface)用作实体(EF 不支持),通常会出现此错误。 CrewMember 实际上是一个接口(interface)吗?

如果它不是接口(interface),而是派生自接口(interface)的类,则 EF 可能会在某些时候感到困惑。也许你在做任何流利的配置?也许您正在尝试映射到会引发此​​错误的基类或接口(interface)?

你的代码实际上有点困惑,因为你应该使用“工作单元”,但你直接访问你的 dbcontext,因此有效地绕过了 UoW,然后在 UoW 上调用 Commit() .. . 我建议您可能需要在这里重新考虑您的数据设计,并且可能完全摆脱 UoW,因为 EF 已经是一个工作单元。

关于c# - EntityCollection - ICollection<InterfaceTEntity> - 运行时问题/怪癖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25852499/

相关文章:

java - 载体和界面多态性

c# - Android:使用缩放和平移的 Canvas 获取正确的坐标

c# - 如何解决 "Service not available, closing transmission channel. The server response was: Server busy, too many connections"

asp.net-mvc - Entity Framework 不将值插入可为空的日期时间字段

entity-framework - EF Code First 4.3 DbContext 生命周期?

c++ - 具有 3D vector 参数的 C++ 和 Lua 函数之间的接口(interface)

c# - 如何使用 Entity Framework Core 配置其他用户定义的数据类型?

c# - 有没有办法找出DateTime变量对应的日历?

asp.net - ASP.NET MVC + Entity Framework中Include()的用途

java - Jax-WS 接口(interface)作为参数