How to Query CRM 2011 EntityCollection in LINQ - dynamics-crm

I am trying to query a EntityCollection / PartyList using LINQs and have had no luck figuring out how to do it.
My query is:
var linqQuery = (from r in gServiceContext.CreateQuery("campaignresponse")
select new
{
activityid = !r.Contains("activityid") ? string.Empty : r["activityid"],
CustomerId = !r.Contains("customer") ? string.Empty : r["customer"]
});
CustomerId is the PartyList / EntityCollection. If I run that code I get, Microsoft.Xrm.Sdk.EntityCollection instead of my actual data. Any ideas on how to query the EntityCollection in LINQ and return the data? Thanks!

The EntityCollection has the property Entities which contains the retrieved data.
EntityCollection.Entities
Edit:
So for example:
var result = service.RetrieveMultiple(query).Entities
.Select(e =>
new
{
firstname = e.Attributes["firstname"],
lastname = e.Attributes["lastname"]
});

Related

ef6 linq method returning $ref for nested entries in query

my linq method system from EF6 is returning $ref when I monitor results in fiddler. If I watch the local window in my webapi everything is populated correctly, but not in the actual results that are returned. It only affects the nested entries. anyone know what I am doing wrong? (I created models from database in EF6)
var student = dbEF.Accounts
.Where(x => x.AccountNumber == acctNum)
.Select(x => new DTOCrmDetails()
{
AccountNumber = x.AccountNumber,
CommissionId = x.CommissionId,
Commission = x.Commission,
ManagerID = x.ManagerID,
ManagerName = x.Manager.ManagerName,
Manager = x.Manager,
Employees = x.Manager.Employees,
WireInstructionsUSD = x.Manager.WireInstructionsUSDs
//Mapping_ManagersExecutingBrokers = x.Manager.Mapping_ManagersExecutingBrokers
}).FirstOrDefault();
return student;
these are my settings.
var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; config.Formatters.Remove(config.Formatters.XmlFormatter); config.Formatters.JsonFormatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
You need to disable your lazy loading in the entity framework dbcontext.
something like this way:
dbEF.Configuration.LazyLoadingEnabled = false;

Translating LINQ query into CRM QueryExpression while using 'select new'

I've got the following container class:
public class AssetAndItsDepositsContainer
{
public jp_asset Asset { get; set; }
public jp_deposit Deposit { get; set; }
}
Is there a way to take the following LINQ query:
from a in serviceContext.jp_assetSet
join d in serviceContext.jp_depositsSet on a.Id equals d.jp_assetid.Id
where a.statecode == jp_assetState.Active &&
a.jp_isonhold = true
select new AssetAndItsDepositsContainer()
{
Asset = a,
Deposit = d
})
.ToList();
And "translate" it by using QueryExpression?
This is what I came up with so far, but I don't know how to mimic the select new expression:
QueryExpression query = new QueryExpression(jp_asset.EntityLogicalName);
query.ColumnSet = new ColumnSet(true);
query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)jp_assetState.Active);
query.Criteria.AddCondition("jp_isonhold", ConditionOperator.Equal, true);
LinkEntity link = query.AddLink(jp_deposit.EntityLogicalName, "Id", "jp_assetid", JoinOperator.Inner);
// Now what?
var res = service.RetrieveMultiple(query).Entities; // gets only jp_assets
You can't access an entire LinkEntity, you can only access its attributes as AliasedValue properties on the main Entity itself.
I would simply retrieve the Id of the second record you're looking for as part of an EntityReference and then execute a Retrieve.
You can actually construct valid Entity objects from linked entities. The only requirement is that the primary key of the linked entity must be available in the result set.
So, your code snippet could be extended like this:
var query = new QueryExpression(jp_asset.EntityLogicalName);
query.ColumnSet.AllColumns = true;
query.Criteria.AddCondition("statecode", ConditionOperator.Equal, (int)jp_assetState.Active);
query.Criteria.AddCondition("jp_isonhold", ConditionOperator.Equal, true);
LinkEntity link = query.AddLink(jp_deposit.EntityLogicalName, "Id", "jp_assetid", JoinOperator.Inner);
link.EntityAlias = "d";
link.Columns.AddColumns("jp_depositid", "jp_name");
IEnumerable<Entity> deposits = Service.RetrieveMultiple(query).Entities
.Select(e => new Entity("jp_deposit")
{
Id = (Guid)e.GetAttributeValue<AliasedValue>("d.jp_depositid").Value,
["jp_name"] = e.GetAttributeValue<AliasedValue>("d.jp_name")?.Value
});
Note
The example above will only work reliable for inner joins. In the result set the primary key (ID) for the linked entity will always be available. Therefore it is safe to get its value using the .Value syntax. All other attribute values can be retrieved using ?.Value.
For left joins you would need to filter the result set first before performing the Select.

CRM Linq find all parents that have 0 children

How can I find (preferably using CRM Linq) parent entities that have 0 children. For example how can I find all accounts that have 0 contacts.
If you are going to use the query expression route, which I would recommend then the following code will be useful
var entityAlias = "con";
var query = new QueryExpression
{
EntityName = "account",
ColumnSet = new ColumnSet(true),
Criteria =
{
FilterOperator = LogicalOperator.And,
Conditions =
{
new ConditionExpression(entityAlias, "contactid",ConditionOperator.Null)
}
}
LinkEntities =
{
new LinkEntity
{
EntityAlias = entityAlias,
LinkFromEntityName = "account",
LinkFromAttributeName = "accountid",
LinkToEntityName = "contact",
LinkToAttributeName = "parentcustomerid",
Columns = new ColumnSet("parentcustomerid", "contactid"),
JoinOperator = JoinOperator.LeftOuter,
}
},
};
var response = service.RetrieveMultiple(query);
var accounts = response.Entities;
In this code I have not limited the columns, this will reduce performance and you should only return the columns needed.
If there is the case for more than 5000 records are going to be returned then you will need to use paging and loop the query to find all the entities,
This can be found here:
https://msdn.microsoft.com/en-us/library/gg327917.aspx
However if you are certain you want to use LINQ then you can use the following code:
public static IEnumerable<Account> FindAccountsWithNoContacts()
{
var contactRelationship = new Relationship("contact_customer_accounts");
foreach(var account in XrmContext.AccountSet)
{
XrmContext.LoadProperty(contactRelationship);
if(!account.RelatedEntities.ContainsKey(contactRelationship)
yield return account;
}
}
My problem with the LINQ code is that all the enities, both the account and contact entities, will be loaded into memory. With large entity sets this can cause OutOfMemoryException, whereas the query expression route will pass the query to the Dynamics server to execute; which should make the execution of the code faster.
The thing you are looking for is left outer join. Which is unfortunately not possible in CRM using LINQ. However you can do it using query expression or FetchXML.
Here is a link that can help you:
https://community.dynamics.com/crm/b/gonzaloruiz/archive/2014/02/23/all-about-outer-join-queries-in-crm-2011-and-crm-2013

Does LINQ SELECT support System.Web.UI.AttributeCollection

I'm trying to populate attributes collection in a LINQ SELECT query.
appointments.AddRange(db.Events.ToList().Select(appointment => new Appointment
{
ID = appointment.ID,
Subject = appointment.Subject,
Attributes["Location"] = appointment.Location
}));
Is this supported?
Thanks.

Using LINQ to pull MembershipUser.Username into a new object

I have the following code and I need to pull out each user's username from the membership tables:
var results = (from u in db.U_USER
where u.Forename.ToLower().Contains(search)
|| u.Surname.ToLower().Contains(search)
select new ExUser
{
MembershipId = u.MembershipId,
Surname = u.Surname,
Forename = u.Forename,
Username = Membership.GetUser(u.MembershipId).UserName
});
Now I know why im getting the following, but can anybody recommend a solution?
LINQ to Entities does not recognize the method 'System.Web.Security.MembershipUser GetUser
LINQ to Entities is trying to translate your select expression into T-SQL, which it can't because there's no ExUser etc. in T-SQL.
Finhish off the expression with a call to AsEnumerable or similar, and then perform the projection:
var results = (from u in db.U_USER
where u.Forename.ToLower().Contains(search)
|| u.Surname.ToLower().Contains(search)
select u)
.AsEnumerable()
.Select(u => new ExUser
{
MembershipId = u.MembershipId,
Surname = u.Surname,
Forename = u.Forename,
Username = Membership.GetUser(u.MembershipId).UserName
});
You can do it by forcing the results into memory by using AsEnumerable. When the results are in memory you can call Membership.GetUser without linq attempting to translate it to sql:
var results = (from u in db.U_USER
where u.Forename.ToLower().Contains(search) || u.Surname.ToLower().Contains(search)
).AsEnumerable().Select(u => new ExUser {
MembershipId = u.MembershipId,
Surname = u.Surname,
Forename = u.Forename,
Username = Membership.GetUser(u.MembershipId).UserName
});

Resources