【发布时间】:2014-10-03 01:29:40
【问题描述】:
考虑以下代码:
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() 附加到第一个返回并不重要,我只是不断收到异常。因此,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 中,并在其中重新编写了查询代码。感谢来自 LinqPad 的惊人的 .Dump() 方法,我能够观察到返回的对象到底是什么。所以第一个返回默认返回DbQuery<T>,第二个返回默认返回IList<T>。具有讽刺意味的是,当我在 LinqPad 中调用完全相同的代码序列时,异常被 not 抛出,我得到了我期待的 ListWrapper。我真的不确定为什么它在 ASP.NET MVC 中不起作用。虽然我什至不确定这是 ASP.NET 的错,因为它在不同程序集中的库项目的代码中崩溃了......
我仍然不知道如何解决这个异常,因为 LinqPad 没有出现问题。不确定这是否重要,但我在解决方案中的所有项目中都针对 .NET 4.5.2,所以我不确定它是否与此有关?
【问题讨论】:
-
ContactListModel 和 Mapper 的代码在哪里?
-
嫌疑人夫妇 -
IgnoreAllUnmapped是一个自定义扩展,可能无法处理投影。其次,确保您在启动期间注册了配置文件。第三,我想知道这些internal和sealed关键字是否会导致任何问题。 -
我为
IgnoreAllUnmapped的代码添加了另一个更新。删除它并手动忽略目标属性没有效果,它仍然抛出异常。配置文件也在开始时使用WebActivator注册方式。最后,我不相信这是internal或sealed关键字,但我会在没有它们的情况下试一试。它不起作用,使其publicunsealed 也没有效果。 -
您也可以尝试使用EFProfiler 来查看生成了哪些查询。这可能会提供一些线索。
-
我想我已经缩小了一些线索(更新 3),但我仍然没有关于如何解决这个异常的答案......
标签: c# asp.net-mvc automapper