使用LINQ从微软CRM中检索数据时得到奇怪的行为[英] Getting weird behavior when retrieving data from Microsoft CRM using LINQ

本文是小编为大家收集整理的关于使用LINQ从微软CRM中检索数据时得到奇怪的行为的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我在使用linq

访问联系实体时遇到了这个问题.

i具有下面的两个功能.

如果我运行了第一个功能,然后将第二个功能称为第二个功能,那么我似乎在第二查询中缺少很多字段.像名称和姓氏一样,没有出现.它们只是显示为空值.如果我自己运行第二个功能,我将获得正确的数据.在两个运行中正确显示的唯一字段是ID,ContactID和new_username.

如果我自己运行第二个功能,我将获得正确的数据.

有什么想法我在做什么错?

非常感谢

这是两个函数

    public List<String> GetContactsUsernameOnly()
    {
        IQueryable<String> _records = from _contactSet in _flinsafeContext.ContactSet
                                       where
                                           _contactSet.new_FAN == "username"
                                       orderby _contactSet.new_username
                                       select _contactSet.new_username;

        return _records.ToList();
    }

    public List<Contact> GetContacts()
    {
        IQueryable<Contact> _records = from _contactSet in _flinsafeContext.ContactSet
                                       where
                                           _contactSet.new_FAN == "my-username-here"
                                       orderby _contactSet.new_username
                                       select _contactSet;

        return _records.ToList();
    }

推荐答案

这是因为当您调用这两种方法时,您正在重复使用相同的CRM上下文(在您的情况下_flinsafecontext)

上下文所做的是缓存记录,因此第一个方法是返回您的联系人,但仅带回new_username字段.

第二种方法希望返回整个记录,但是当第一个记录在第一个记录之后调用时,记录在上下文中已经存在,因此尽管仅填充一个字段,但它只是返回的.它不够聪明,无法懒惰地加载尚未填充的字段.如果首先调用此方法,则它在上下文中不存在,因此将返回整个记录.

有两种解决方法:

1)不要重复使用CRMContext.而是基于单身人士iorganizationservice在每种方法中创建一个新方法.

2)上下文上有一个clearchanges()方法,这意味着下次进行查询时,它将返回CRM并获取您选择的字段.这也将清除所有未保存的创建/更新/删除等,因此您必须谨慎围绕上下文所在的状态.

顺便说一句,创建新的CRM上下文不是一个密集的操作,因此通常不值得通过环境并重复使用它们.它正在创建最慢的基础组织服务.

这种行为可能是如此痛苦,因为返回整个记录的效率非常低,因此您只想选择每个查询所需的字段.

其他推荐答案

,这是您仅返回想要的字段的方式:

IEnumerable<ptl_billpayerapportionment> bpas = context.ptl_billpayerapportionmentSet
.Where(bm => bm.ptl_bill.Id == billId)
.Select(bm => new ptl_billpayerapportionment()
{
    Id = bm.Id,
    ptl_contact = bm.ptl_contact
})

这将确保在上下文中执行较小的SQL语句,因为ID和PTL_CONTACT是仅返回的两个字段.但是正如Ben上面所说,在同一上下文中针对同一实体的进一步检索将返回初始选择中未包含的字段(根据OP的问题).

对于奖励积分,使用iEnumerable并创建一个新的,轻巧的实体使您可以访问通常的LINQ方法,例如.

本文地址:https://www.itbaoku.cn/post/1556992.html

问题描述

I'm having this problem accessing the Contact entity using LINQ.

I have the 2 functions below.

If I ran the 1st function and then call the 2nd one, I seemed to be missing a lot of fields in the 2nd query. Like firstname and lastname are not showing up. They just shows up as null values. If I ran the 2nd function on its own, I am getting the right data. The only fields that shows up correctly in both runs are Id, ContactId and new_username.

If I ran the 2nd function on its own, I am getting the right data.

Any ideas what am I doing wrong?

Thanks a lot

Here are the 2 functions

    public List<String> GetContactsUsernameOnly()
    {
        IQueryable<String> _records = from _contactSet in _flinsafeContext.ContactSet
                                       where
                                           _contactSet.new_FAN == "username"
                                       orderby _contactSet.new_username
                                       select _contactSet.new_username;

        return _records.ToList();
    }

    public List<Contact> GetContacts()
    {
        IQueryable<Contact> _records = from _contactSet in _flinsafeContext.ContactSet
                                       where
                                           _contactSet.new_FAN == "my-username-here"
                                       orderby _contactSet.new_username
                                       select _contactSet;

        return _records.ToList();
    }

推荐答案

It is because you are reusing the same CRM context when you call both methods (in your case _flinsafeContext)

What the context does is cache records, so the first method is returning your contact but only bringing back the new_username field.

The second method wants to return the whole record, but when it is called after the first one the record already exists in the context so it just returns that, despite only having the one field populated. It is not clever enough to lazy load the fields that have not been populated. If this method was called first, it doesn't exist in the context so will return the whole record.

There are 2 ways to get around this:

1) Don't reuse CRMContexts. Instead create a new one in each method based on a singleton IOrganizationService.

2) There is a ClearChanges() method on your context that will mean the next time you do a query it will go back to CRM and get the fields you have selected. This will also clear any unsaved Created/Updates/Deletes etc so you have to be careful around what state the context is in.

As an aside, creating a new CRM Context isn't an intensive operation so it's not often worthwhile passing contexts around and reusing them. It is creating the underlying OrganisationService that is the slowest bit.

This behaviour can be so painful, because it is horribly inefficient and slow to return the entire record so you WANT to be selecting only the fields you want for each query.

其他推荐答案

And here's how you return just the fields you want:

IEnumerable<ptl_billpayerapportionment> bpas = context.ptl_billpayerapportionmentSet
.Where(bm => bm.ptl_bill.Id == billId)
.Select(bm => new ptl_billpayerapportionment()
{
    Id = bm.Id,
    ptl_contact = bm.ptl_contact
})

This will ensure a much smaller sql statement will be executed against the context as the Id and ptl_contact are the only two fields being returned. But as Ben says above, further retrievals against the same entity in the same context will return nulls for fields not included in the initial select (as per the OP's question).

For bonus points, using IEnumerable and creating a new, lightweight, entity gives you access to the usual LINQ methods, e.g. .Any(), .Sum() etc. The CRM SDK doesn't like using them against var datasets, apparently.