2

I have encountered a LINQ issue and hope that you can help me to figure it out.

Here is what is happening.

  1. I get an IQueryable<LicenseEntity> of entities from the repository.
  2. I look at the fields in these entities and see that they contain valid data. There is a field for a related entity Customer in the LicenseEntity. It contains valid data, too, because I loaded it with the LicenseEntity.
  3. I use .Select to project each LicenseEntity to a LicenseViewModel.
  4. For each LicenseEntity, a LicenseEntity is passed into AutoMapper.Mapper.Map and is loaded into a LicenceViewModel entity.
  5. After all of the entities have been processed, when I look at the list of LicenseViewModels in the debugger, it reports a null reference exception and there are no items to view.
  6. To determine whether AutoMapper what causing my problem, I replaced it with a MapMe(). When I stopped at the return statement in MapMe and looked at the s parameter, which is the original entity, I found that the data in it is okay except that the customer field is now null. I assume that Select has done something that I don't know about.

How I can make Select retain all of the information in the original entity when it is doing its projection? Our solution cannot materialize the list because it may be very, very large. I've included my test code below and would really appreciate your help.

// Get the IQueryable<LicenseEntity> list of licenses from the repository.
var list = LicenseRepository.List();

// Convert the IQueryable<LicenseEntity> to an IQueryable<LicenseViewModel>
var vmlist = list.Select(x => MapMe(x, new LicenseViewModel()));
//var vmlist = list.Select(x => AutoMapper.Mapper.Map(x, new LicenseViewModel()));

// This function was used to see the LicenseEntity that was passing into Map().
// I discovered that the entity has all the correct data except for a related
// entity field, which was present in the original LicenseEntity before         
public LicenseViewModel MapMe(LicenseEntity s, LicenseViewModel d)
{
    return d;
}

The following code works properly however it materializes the entities, which we cannot do.

List<LicenseViewModel> vms = new List<LicenseViewModel>();
foreach (var item in list)
{
    var vm = AutoMapper.Mapper.Map(item, new LicenseViewModel());
    vms.Add(vm);
}
4

3 回答 3

1

您已对此进行了标记,LINQ-to-Entities但文本中没有提及底层技术。但是问题很可能是由关联对象的延迟加载引起的。

这是适用于我使用过的大多数 ORM 的设计选择。加载对象时,默认情况下不加载连接的对象。如果它们是默认加载的,很明显你会很快破坏一切

  • 当您加载许可证时,相关的客户会自动加载
  • 加载客户时,加载所有相关对象 - 公司、地址、所有其他许可证等
  • 对于这些对象中的每一个,都会加载每个相关的对象......

答案是您需要指定要加载哪些相关对象。在实体框架中,您可以使用Include方法执行此操作。

因为您使用的是存储库抽象,所以您可能会发现这比需要的更困难,但在不了解更多信息的情况下,我无法提供任何建议。这种类型的功能——非常基本的东西——对于存储库和“工作单元”模式来说总是一个困难。

于 2012-11-30T04:08:53.450 回答
0

我找到了将域实体投影到视图模型的解决方案。如果您遇到与我相同的问题,请查看以下链接:

http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/ http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-代码

顺便说一句,在我的域实体中,我有一个带有一些“计算”属性的部分类......其值是从数据库记录中的其他字段生成的属性。这些不能在域实体中,因为它们会干扰上述解决方案。我将它们移至我的 ViewModel 类,这是真正需要它们的地方,一切都很好。

希望这些信息能帮助...

麦克风

于 2012-12-01T07:09:27.860 回答
0

我认为您的映射应该更像:

var vms = Mapper.Map<List<LicenseEntity>, List<LicenseViewModel>>(list);

(即 - 你不需要foreach循环)。

但不幸的是,我非常怀疑这是否会解决您的问题,因为我怀疑这也会实现您的实体。

于 2012-11-30T04:15:36.817 回答