[英]Using AutoMapper QueryableExtensions with Entity Framework in ASP.NET MVC causes an “Operation could destabilize the runtime” exception
考虑以下代码:
protected override IEnumerable<IListModel> GetListInternal(
IQueryModel2<Contact> queryModel) {
/// Causes exception
return this.Query(queryModel).Project().To<ContactListModel>().AsEnumerable();
/// Does not cause exception
return Mapper.Map<IQueryable<Contact>, IEnumerable<ContactListModel>>(this.Query(queryModel)).ToList();
}
当第一行返回时,我得到一个例外: 操作可能会使运行时不稳定 。 当第二行返回时,它工作正常。 据我了解,第二个返回实际上返回一个具体的IEnumerable<ContactListModel>
,但第一个返回没有返回。 我将.AsEnumerable()
, ToArray()
或.ToList()
附加到第一个返回值.ToList()
,我一直在获取异常。 因此,关于Project()
返回的内容必须有所了解。 无论返回什么,都可能是IEnumerable<ContactListModel>
从而传递了方法的返回要求,但是当它在管道中进行进一步处理时,它的具体对象正在引发异常。
具体来说,此方法返回的集合将传递到进行最终处理的ListWrapper<TEntity>
类。 当我在集合上调用.Count()
时,总是会抛出异常。
我急切地寻求有关解决投影问题的指导,因为第二次回报效率很低。 从MiniProfiler告诉有关使用此特定代码的页面的信息,我正在进行1204条重复的SQL查询,我想我们所有人都可以同意这是一个问题...谢谢您的任何建议!
这是Query()
和IQueryModel2<TEntity>
样子:
public IQueryable<TEntity> Query(
IQueryModel2<TEntity> queryModel = null) {
return this.QueryInternal(queryModel);
}
private IQueryable<TEntity> QueryInternal(
IQueryModel2<TEntity> queryModel) {
IQueryable<TEntity> entities = this.Context.Set<TEntity>();
if (queryModel != null) {
if (queryModel.Entities != null) {
entities = queryModel.Entities.AsQueryable();
}
if (queryModel.Predicate != null) {
entities = entities.AsExpandable().Where(queryModel.Predicate);
}
}
return entities;
}
public interface IQueryModel2<TEntity> {
IEnumerable<TEntity> Entities { get; set; }
Expression<Func<TEntity, bool>> Predicate { get; set; }
SearchPostModel Search { get; set; }
}
更新(1)
public sealed class ContactListModel :
ListModel {
[Display(Order = 3)]
public string Email { get; set; }
[Display(Order = 1)]
public string Name { get; set; }
[Display(Order = 2)]
public string Phone { get; set; }
[Display(Order = 4)]
public ContactType ContactType { get; set; }
}
internal sealed class ContactToContactListModel :
Profile {
protected override void Configure() {
base.Configure();
base.CreateMap<Contact, ContactListModel>()
.ForMember(
d => d.Name,
o => o.MapFrom(
s => (s.FirstName + " " + s.LastName)))
.IgnoreAllUnmapped();
}
}
更新(2)
public static class AutoMapperExtensions {
public static IMappingExpression<TSource, TDestination> IgnoreAllUnmapped<TSource, TDestination>(
this IMappingExpression<TSource, TDestination> expression) {
if (expression == null) {
return null;
}
return IgnoreAllUnmappedInternal<TSource, TDestination>(expression, typeof(TSource), typeof(TDestination));
}
private static IMappingExpression<TSource, TDestination> IgnoreAllUnmappedInternal<TSource, TDestination>(
IMappingExpression<TSource, TDestination> expression,
Type sourceType,
Type destinationType) {
IEnumerable<string> unmappedProperties = Mapper.GetAllTypeMaps().First(
m =>
m.SourceType.Equals(sourceType)
&& m.DestinationType.Equals(destinationType)).GetUnmappedPropertyNames();
foreach (string unmappedProperty in unmappedProperties) {
expression.ForMember(unmappedProperty, o => o.Ignore());
}
return expression;
}
}
更新3
因此,我将项目的程序集加载到LinqPad中,并在其中重新编码了查询代码。 多亏了.Dump()
出色的.Dump()
方法,我才能够观察到返回的对象实际上是什么。 因此,第一个返回默认返回DbQuery<T>
,第二个默认返回IList<T>
。 具有讽刺意味的是,当我在LinqPad中调用完全相同的代码序列时, 不会引发异常,并且得到了我期望的ListWrapper。 我真的不确定为什么它在ASP.NET MVC中不起作用。 尽管我什至不确定这是ASP.NET的错,因为它崩溃了属于不同程序集的库项目的代码...
由于LinqPad并未出现问题,因此我对如何解决此异常一无所知。 不知道这是否重要,但是我打算在解决方案中的所有项目中使用.NET 4.5.2,所以我不确定是否与此有关。
将Automapper升级到v3.2.0。
那解决了我遇到的确切问题。
对于从Automapper版本7.0.1开始在AzureDevOps的构建管道中使用VSTest平台运行的测试(mstest运行良好),返回了相同的例外。 支持这些测试的Automapper的最新版本是6.2.2。
从其他答案和他们的github问题来看,在我看来这是一个回归错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.