实体框架4.1 - 动态预先加载

时间:2011-12-20 20:32:45

标签: c#-4.0 entity-framework-4.1

我有一个实体框架模型(已排除某些属性以保持简单):

public class Media
{
    public int MediaID { get; set; }
    public ICollection<Track> Tracks { get; set; }
    public ICollection<RelatedMedia> RelatedMedias { get; set; }
}

然后我有我的DbContext:

public class MediaServiceContext : DbContext
{
    public DbSet<Media> Medias { get; set; }
}

然后,我可以使用以下内容检索数据,效果很好:

public Media Media_Get(int id)
    {
        using (MediaServiceContext mc = new MediaServiceContext())
        {
            return mc.Medias.Include("Tracks").Include("RelatedMedias").Single(m => m.MediaID == id);
        }
    }

我的问题是,在某些情况下,我可能不想加载一个或两个相关实体,具体取决于我的应用程序的哪个部分正在调用此代码;如何使包含动态?

我试过这个:

public Media Media_Get(int id, bool includeRelated, bool includeTracks)
    {                  
        using (MediaServiceContext mc = new MediaServiceContext())
        {
            IQueryable<Media> query = mc.Medias;

            if (includeRelated)
                query = query.Include("RelatedMedias");

            if (includeTracks)
                query = query.Include("Tracks");

            return query.Single(m => m.MediaID == id);
        }
    }

...但是我收到了“指定的无效投射”例外。

我也尝试了this提出的解决方案,但它产生了一个'无法将DbQuery转换为ObjectQuery'异常。将链接解决方案中的扩展方法从'(ObjectQuery)source'更改为'(DbQuery)source'然后导致相同的'指定的强制转换为无效' 例外。

我已经寻求解决方案,但没有运气。任何帮助将不胜感激。

修正案 - 这是堆栈跟踪:

   at System.Data.SqlClient.SqlBuffer.get_Int64()
   at lambda_method(Closure , Shaper )
   at System.Data.Common.Internal.Materialization.Coordinator.HasNextElement(Shaper shaper)
   at System.Data.Common.Internal.Materialization.Shaper`1.RowNestedResultEnumerator.MoveNext()
   at System.Data.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.TryReadToNextElement()
   at System.Data.Common.Internal.Materialization.Shaper`1.ObjectQueryNestedEnumerator.MoveNext()
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source)
   at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source, Expression`1 predicate)
   at API.Areas.V1.Models.RetailerManager.Media_Get(Int32 id, String retailerKey, Boolean includeLicenses, Boolean includeProperties, Boolean includeRelated, Boolean includeTracks) in C:\Users\garth\Documents\Development\WebApplications\api\Areas\V1\Models\RetailerManager.cs:line 28
   at API.Areas.V1.Controllers.RetailerController.Media(Nullable`1 id, String httpVerb, Boolean includeLicenses, Boolean includeProperties, Boolean includeRelated, Boolean includeTracks) in C:\Users\garth\Documents\Development\WebApplications\api\Areas\V1\Controllers\RetailerController.cs:line 25
   at lambda_method(Closure , ControllerBase , Object[] )
   at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)

1 个答案:

答案 0 :(得分:1)

您的堆栈跟踪显示.SingleOrDefault()导致此异常,但我在您的代码中看不到.SingleOrDefault()

我确实看到了这个:

return query.Single(m => m.MediaID == id);

Media.MediaID可能是long而不是int吗?

<强>更新

作为回答原始问题的另一种选择,我answered a question a couple of weeks ago in relation to this。我的答案中的示例代码与动态排序有关,但我们使用非常相似的模式进行动态预先加载(请参阅我的回答后的第一条评论)。

而不是像这样的方法签名:

public Media Media_Get(int id, bool includeRelated, bool includeTracks)

您的签名看起来更像是这样:

public Media Media_Get(MediaGetter mediaGetter)

......你会像这样使用它:

var media = someInstance.Media_Get(
    new MediaGetter { ID = id, }
        .EagerLoad(m => m.Tracks)
        .EagerLoad(m => m.RelatedTracks)
);