是否可以在EntityFrameworkCore中创建基于字符串的Include替代方案?在API上,我需要动态包含,但EFCore不支持基于字符串的包含。所以我创建了一个映射器,将字符串映射到添加到列表的lambda表达式:Listexpressions=newList
();考虑这个特定类型:publicclassEFContext{publicDbSetP1s}publicDbSetP2s{get;放;}publicDbSetP3s{get;放;}}publicclassP1{publicP2P2{get;放;}公共P3P3{得到;P2{公共P3P3{得到;放;}}publicclassP3{}Include和ThenInclude通常使用如下:EFContextefcontext=newEFContext();IQueryable结果=efcontext.P1s.Include(p1=>p1.P2).ThenInclude(p2=>p2.P3).Include(p1=>p1.P3);它们也可以按以下方式使用:Expression
expressions=newList
{newList{p1p2,p1p3},newList{p2p3}};EFContextefcontext=newEFContext();IIncludableQueryableq1=EntityFrameworkQueryableExtensions.Include(efcontext.P1s,p1p2);IIncludableQueryableq2=EntityFrameworkQueryableExtensions.ThenInclude(q1,p2p3);IIncludableQueryableq3=EntityFrameworkQueryableExtensions.Include(q2,p1p3);结果=q3.AsQueryable();问题是我的方法接收到一个表达式列表列表,而我在T中只有基本类型:.GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions)..GetParameters().Any(pi=>pi.Name=="navigationPropertyPath"));MethodInfoincludeAfterCollection=typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.ThenInclude)).Single(mi=>.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter);MethodInfoincludeAfterReference=typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethods(nameof(实体yFrameworkQueryableExtensions.ThenInclude).Single(mi=>mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter);foreach(表达式中的列表路径){Booleanstart=true;foreach(Expressionexpressioninpath){if(start){MethodInfomethod=include.MakeGenericMethod(typeof(T),((LambdaExpression)expression).ReturnType);IIncludableQueryableresult=method.Invoke(null,newObject[]{collection,expression});开始=假;}else{MethodInfomethod=includeAfterReference.MakeGenericMethod(typeof(T),typeof(?),((LambdaExpression)expression).ReturnType);IIncludableQueryableresult=method.Invoke(null,newObject[]{collection,expression});}}}返回集合;//(将被final替换为可查询的)}}主要问题是为每个Include和ThenInclude步骤找出正确的类型,以及要使用哪个ThenInclude...这对于当前的EF7Core是否可行?有没有人找到动态包含的解决方案?Include和ThenIncludeAfterReference以及ThenIncludeAfterCollection方法位于EntityFrameworkGithub存储库中ityFrameworkQueryableExtensions类的一部分更新:从v1.1.0开始,基于字符串的包含现在是EFCore的一部分,因此下面的问题和解决方案已过时。原答案:周末的趣味运动。理解:我最终得到了以下扩展方法:.Any(pi=>pi.Name=="navigationPropertyPath"));privatestaticreadonlyMethodInfoIncludeAfterCollectionMethodInfo=typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.ThenInclude)).Single(mi=>!mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter);privatestaticreadonlyMethodInfoIncludeAfterReferenceMethodInfo=typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethods(nameof(EntityFrameworkQueryableExtensions.ThenInclude)).Single(mi=>mi.GetParameters()[0].ParameterType.GenericTypeArguments[1].IsGenericParameter);publicstaticIQueryableInclude(这个我可查询源,paramsstring[]propertyPaths)whereTEntity:class{varentityType=typeof(TEntity);对象查询=来源;foreach(varpropertyPathinpropertyPaths){类型prevPropertyType=null;foreach(varpropertyNameinpropertyPath.Split('.')){输入参数类型;方法信息方法;if(prevPropertyType==null){parameterType=entityType;方法=IncludeMethodInfo;}else{parameterType=prevPropertyType;方法=IncludeAfterReferenceMethodInfo;if(parameterType.IsConstructedGenericType&¶meterType.GenericTypeArguments.Length==1){varelementType=parameterType.GenericTypeArguments[0];varcollectionType=typeof(ICollection).MakeGenericType(elementType);如果(collectionType.IsAssignableFrom(parameterType)){parameterType=elementType;方法=IncludeAfterCollectionMethodInfo;}}}varparameter=Expression.Parameter(parameterType,"e");varproperty=Expression.PropertyOrField(parameter,propertyName);如果(prevPropertyType==null)method=method.MakeGenericMethod(entityType,property.Type);elsemethod=method.MakeGenericMethod(entityType,parameter.Type,property.Type);query=method.Invoke(null,newobject[]{query,Expression.Lambda(property,parameter)});prevPropertyType=property.Type;}}返回(IQueryable)查询;}}测试:模型:publicclassP{publicintId{get;放;}公共字符串信息{得到;放;}}publicclassP1:P{publicP2P2{get;放;}公共P3P3{得到;放;}}publicclassP2:P{publicP4P4{get;放;}公共ICollectionP1s{得到;放;}}publicclassP3:P{publicICollectionP1s{get;放;}}publicclassP4:P{publicICollectionP2s{get;放;}}publicclassMyDbContext:DbContext{publicDbSetP1s{get;放;}publicDbSetP2s{get;放;}publicDbSetP3s{get;放;}publicDbSetP4s{get;放;}//...受保护的覆盖voidOnModelCreating(ModelBuildermodelBuilder){modelBuilder.Entity().HasOne(e=>e.P2).WithMany(e=>e.P1s).HasForeignKey("P2Id").IsRequired();modelBuilder.Entity().HasOne(e=>e.P3).WithMany(e=>e.P1s).HasForeignKey("P3Id").IsRequired();modelBuilder.Entity().HasOne(e=>e.P4).WithMany(e=>e.P2s)。HasForeignKey("P4Id").IsRequired();base.OnModelCreating(模型构建器);}}用法:vardb=newMyDbContext();//使用Include/ThenInclude的示例查询varqueryA=db.P3s.Include(e=>e.P1s).ThenInclude(e=>e.P2).ThenInclude(e=>e.P4).Include(e=>e.P1s).Include(e=>e.P1s)e.P1s).ThenInclude(e=>e.P3);//使用字符串的相同查询IncludesvarqueryB=db.P3s.Include("P1s.P2.P4","P1s.P3");这是如何工作的:给定类型为TEntity和Prop1.Prop2...PropNforms的字符串属性路径,我们拆分路径并执行以下操作:对于第一个属性,我们只需通过反射调用EntityFrameworkQueryableExtensions.Include方法:publicstaticIIncludableQueryableInclude(这个IQueryable源,Expression>navigationPropertyPath)并存储结果我们知道TEntity和TProperty是属性的类型。对于下一个属性,它有点复杂。我们需要调用以下ThenInclude重载之一:publicstaticIIncludableQueryableThenInclude(thisIIncludableQueryable>source,Expression>navigationPropertyPath)和publicstaticIIncludableQueryableThenInclude(thisIIncludableQueryablesource,Expression>navigationPropertyPath)其中source是当前结果。TEntity对于所有调用都是相同的。但是什么是TPreviousProperty以及我们如何决定调用哪个方法。好吧,首先我们使用一个变量来记住上一次调用的TProperty。然后我们检查它是否是集合属性类型,如果是,我们调用从集合类型的泛型参数中提取的类型TPreviousProperty的第一个重载,否则只调用该类型的第二个重载。就这样。NothingThenInclude,只是一个通过反射模拟出来的显式Include/ThenInclude调用链。EFCore1.1附带的基于字符串的Include()。我建议您尝试升级并删除您必须添加到代码中以解决此限制的任何变通办法。在您的查询中创建“IncludeAll”扩展需要一种不同于您最初所做的方法。EFCore执行表达式解释。当它看到.Include方法时,它会将此表达式解释为创建其他查询。(请参阅RelationalQueryModelVisitor.cs和IncludeExpressionVisitor.cs)。一种方法是添加一个额外的表达式访问者来处理IncludeAll的扩展。另一种(可能更好)方法是将.IncludeAll中的表达式树解释为适当的.Includes,并让EF正常处理包含。这两种实现都非常重要,超出了SO答案的范围。EFCore1.1附带的基于字符串的Include()。如果保留此扩展名,您将收到错误“找到模糊匹配项”。我花了半天时间寻找解决此错误的方法。最后我删除了上面的扩展,错误解决了。以上是C#学习教程:CanIcreateaString-basedIncludealternativeinEntityFrameworkCore?如果所有分享的内容对你有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处:
