包含涉及同一表的2个连接的子集合导航属性时,列名无效

时间:2014-09-24 22:42:43

标签: c# entity-framework entity-framework-6

我编写了一个存储库GetList函数,适用于大多数导航属性。 但是,当我尝试包含基于实体集合的特定导航属性时,它会失败。

以下涉及多对多关系的域类

[Table("Template")]
public class Template : LoggedEntity
{
    public string Description { get; set; }

    public virtual ICollection<TemplateTask> Tasks { get; set; }
}

[Table("TemplateTask")]
public class TemplateTask : LoggedEntity
{
    [Column("TemplateId")]
    public int TemplateId { get; set; }

    [ForeignKey("TemplateId")]
    public virtual Template Template { get; set; }

    public virtual ICollection<TemplateTaskDependancy>  Dependancies { get; set; }  

    public virtual ICollection<TemplateTaskDependancy> NeededTasks { get; set; }
}

[Table("TemplateTaskDependancy")]
public class TemplateTaskDependancy : LoggedEntity
{
    [Column]
    public int NeededTaskId { get; set; }

    [Column]
    public int TaskId { get; set; }

    [Required]
    [ForeignKey("TaskId")]
    public virtual TemplateTask Task { get; set; }

    [Required]
    [ForeignKey("NeededTaskId")]
    public virtual TemplateTask NeededTask { get; set; }
}

[Table("LoggedEntity")]
public class LoggedEntity
{
    public int Id { get; set; }
}

以下失败

public IList<TemplateTask> GetTaskData()
{
    using (var uow = new UnitOfWork<TemplateContext>())
    using (var repository = new TemplateTaskRepository(uow))
    {
        int templateId = 1;
        return repository.GetList(p => p.Template.Id == templateId,
                                  a => a.Template, 
                                  c => c.Dependancies);  // runtime error occurs if c.Dependancies is included
    }
}

以下作品

public IList<TemplateTask> GetTaskData()
{
    using (var uow = new UnitOfWork<TemplateContext>())
    using (var repository = new TemplateTaskRepository(uow))
    {
        int templateId = 1;
        return repository.GetList(p => p.Template.Id == templateId,
        a => a.Template);   
    }
}

我的存储库类是:

 // based on Julie Lerman's repository pattern
 public class TemplateTaskRepository : LoggedEntityRepositoryBase<TemplateTask>, ITemplateTaskRepository
 {
    public TemplateTaskRepository(IUnitOfWork uow) : base(uow)
    {
    }
}

public interface ITemplateTaskRepository : IEntityRepository<TemplateTask>
{
}

public class LoggedEntityRepositoryBase<T> : IEntityRepository<T> where T : LoggedEntity
{
    private readonly IContext context;
    private readonly bool hasUnitOfWork;

    public LoggedEntityRepositoryBase(IUnitOfWork uow)
    {
        hasUnitOfWork = true;
        context = uow.Context;
    }

    public LoggedEntityRepositoryBase(IContext pContext)
    {
        context = pContext;
    }

    public IContext IContext
    {
        get
        {
            return context;
        }
    }
    public virtual IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties)
    {
        List<T> list;
        IQueryable<T> dbQuery = ((DbContext)context).Set<T>();

        //Apply eager loading
        foreach (var navigationProperty in navigationProperties)
        {
            dbQuery = dbQuery.Include(navigationProperty);
        }

        list = dbQuery.AsNoTracking().Where(where).ToList(); // error occurs here

        return list;
    }
 // etc
}

public interface IEntityRepository<T> : IDisposable where T : class
{
    IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties);
    // etc
}

错误信息如下

System.Data.Entity.Core.EntityCommandExecutionException was unhandled
  HResult=-2146232004
  Message=An error occurred while executing the command definition. See the inner exception for details.
  Source=EntityFramework
  StackTrace:
       at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
       at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
       at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
       at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
       at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at SyriusData.LoggedEntityRepositoryBase`1.GetList(Func`2 where, Expression`1[] navigationProperties) in e:\EShared\Dev2013SyriusTest\SyriusTest\SyriusData\LoggedEntityRepositoryBase.cs:line 87
       at SyriusTest.Form1.GetTaskData() in e:\EShared\Dev2013SyriusTest\SyriusTest\SyriusTest\Form1.cs:line 56
       at SyriusTest.Form1.button1_Click(Object sender, EventArgs e) in e:\EShared\Dev2013SyriusTest\SyriusTest\SyriusTest\Form1.cs:line 41
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at SyriusTest.Program.Main() in e:\EShared\Dev2013SyriusTest\SyriusTest\SyriusTest\Program.cs:line 19
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.Data.SqlClient.SqlException
       HResult=-2146232060
       Message=Invalid column name 'TemplateTask_Id'.
       Source=.Net SqlClient Data Provider
       ErrorCode=-2146232060
       Class=16
       LineNumber=29
       Number=207
       Procedure=""
       Server=Myserver\SQL2008R2
       State=1
       StackTrace:
            at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
            at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
            at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
            at System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
            at System.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
            at System.Data.SqlClient.SqlDataReader.get_MetaData()
            at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
            at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
            at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
            at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
            at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
            at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
            at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
            at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
            at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
            at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
            at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
            at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
            at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)

[更新] 我想知道错误是否是由于没有遵循EF的命名约定。如here所示,我认为我已经在TemplateTaskConfiguration类中处理了它[/ p>]

1 个答案:

答案 0 :(得分:0)

问题是我的TemplateContext类没有设置TemplateTaskConfiguration。

我在用于创建数据库的主上下文中完成了它,但是我忘了如果实现了多个上下文,那么它们都需要实现modelBuilder规则。

我的TemplateContext类现在读取

public class TemplateContext : ContextBase<TemplateContext>, ITemplateContext
{
    public DbSet<Template> Templates { get; set; }
    public DbSet<TemplateTask> TemplateTasks { get; set; }
    public DbSet<TemplateTaskDependancy> TemplateTaskDependancies { get; set; }


    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Configurations.Add(new TemplateTaskConfiguration());
    }
}

虽然现在看来显而易见,但我花了一整天时间试图解决这个问题!