Populating DbSet<TEntity>.Local with only specified fields - c#

In Linq to Sql, I would download only a subset of fields for processing in order to reduce query time. Something like this...
var local_data = from row in context.MyTable
select new {
ID = row.ID,
Name = row.Name,
EMAIL = row.EMAIL
};
And then I would simply convert the projected data into a POCO collection...
foreach(var item in local_data){
collection.Add(
new MyTable(){
ID = item.ID,
NAME = item.NAME,
EMAIL = item.EMAIL
};
);
}
This is extremely useful when dealing with massive, unwieldly table records where I only want to pull a handful of columns. When I heard about DbSet<TEntity>.Local, I was eager to switch over from Linq2SQL, but I can't seem to find the version of this new streamlined caching system that allows me to narrow the query scope to specific columns. How would I go about this?

caching system that allows me to narrow the query scope to specific columns
Sorry, the answer is: not possible.
The reason is that EF's internal cache is used for tracking entities, full entities. Being able to access these cached entities through the Local collection is a mere bonus that was introduced with the DbContext API. The cache doesn't exist because of it. The cache is for change tracking.
When EF materialized an entity from the database, it stores its original values into the change tracker and also frequently stores copies of its current values. When it's time to save changes, these values are compared and SQL statements are generated accordingly to store the changes.
Now you know this, you'll understand that EF can't store party populated entities into its cache. How should EF carry out change tracking if an entity can have any random collection of original values and current values?
Also, the result of a projection -- select new -- is never tracked (cached) and, thus, not accessible through a Local collection.
So in this respect you won't gain much by moving to EF.

Related

How to retrieve entities with a subset of related entities?

I have two entities in a one-to-many relation:
Meter (1) -> (n) Reading
I believe my two entities are set up correctly to provide the relation, so assume that.
I wish to retrieve Meters with related Readings but because there may be many Readings per Meter, I wish to limit it by eg Reading.Date. Another option could be to read at most X Readings per Meter.
How can I do that in EF.Core?
What I think the other answer missed is that you are asking for a subset of the related entities, i.e. not the entire collection of related entities.
If you want to be selective about the related entities that are fetched, you cannot just rely on an Include statement (or implicit lazy loading), because these are set up to load all related entities.
There is no selective Include. But you can make an inclusive Select:
DateTime filterDate = DateTime.Now;
var myData = db.Meters
.Select(m => new
{
Meter = m,
Readings = m.Readings.Where(r => r.Date == filterDate)
})
.ToList();
Remarks
I used an anonymous type, but you can of course also use a concrete DTO class.
Where(r => r.Date == filterDate) can be improved (checking for the Date component, or a range), this is just a simple example. You can use whatever filter criteria you want here.
Notice that you do not need an Include statement for this. A Select (on a yet unenumerated IQueryable) does not need an explicit Include because the Select itself is already aware of what data you want to fetch.
I suggest not putting the subset of related entities in the meter.Readings nav prop. This is going to lead to confusion down the line as to whether this list is a subset or the full set, and EF may actually register this as a change when you call SaceChanges(). Nav props should not be used as storage space for collection with the same type but a different functional meaning.
If your tables are designed correctly i.e. key in Meter is mapped with Reading (see foreign key constraints), then EF automatically gives related records when you access its POCO class.
Make sure Reading has foreign key for Meter table in database.

get related data from ms dynamics crm using XRM SDK

I'm trying to retrieve data from crm in a .net application, using the SDK.
I've managed to do simple queries to retrieve lists, but I would now like to get the related entities with items, rather than the ids.
I have tried things like
QueryExpression query = new QueryExpression
{
EntityName = "opportunity",
....
LinkEntity linkEntityAccount = new LinkEntity()
{
LinkFromEntityName = "opportunity",
LinkFromAttributeName = "opportunityid",
LinkToEntityName = "serviceappointment",
LinkToAttributeName = "regardingobjectid",
JoinOperator = JoinOperator.Inner,
Columns = new ColumnSet(new string[] { "scheduledstart", "scheduledend" }),
EntityAlias = "service"
};
query.LinkEntities.Add(linkEntityAccount);
(This will return a collection of entities from the opportunity table)
However the LinkedEntities just put the two columns in the returns entities.
What i would like is (say for this example) is a entity.serviceappointment to be the the entity containing the service appointment entity/data. Instead of in entity there being fields such as service.scheduledstart and service.scheduledend
I have looked at the Relationship and RelationshipQueryCollection things in the SDK but i have been unable to setup a query that will do the query, without first getting the opportunity entities. But it looks like that maybe what I need? I'm not sure.
Is this even possible? Or should I just continue to query entities individually?
Thanks
In the QueryExpression the LinkEntity represents a join. That's why the fields of the joined table are in the Entity row. They can be distinguished from the 'real' entity attributes by the fact that their names are prefixed (including a dot) and their values are wrapped in an AliasedValue object.
It is possible to unwrap them and create strong typed Entity objects, but you will need to write the code yourself.
Alternatively you can consider a few other options:
Query for serviceappointment records and join the opportunity records.
Retrieve opportunity records one by one using the RetrieveRequest and include the query for the related service appointments in the request. (See also this discussion on StackOverflow.)
Create an Action returning all data you need in a convenient OrganizationResponse.
There's no automatic way to get the entire linked entity data (as an Entity object) that I know of (that's not to say it's impossible, mind you).
But I think it'd be a lot easier to just query the data you need in another request.
Find the list of opportunities you need
Use the regarding object IDs as the parameter of an "IN" filter for the second query.

Multiple operations under linq2Entities

I've been using Linq2Entities for quite some time now on small scale programs. So usually my queries are basic (return elements with a certain value in a specific column, add/update element, remove element,...).
Now i'm moving to a larger scale program and given my experience went with Linq2Entities and everything was fine until i had to remove a large number of elements.
In Linq2Entities i can only find a remove method that takes on entity - and so to remove 1000 elemnts i need first to retrieve them then apply a remove one by one then call savechanges.
Either i am missing something or i feel a) this is really bad performance-wise and b) i would be better off making this a procedure in the database.
Am i right in my assumptions? Should massive removals / additions be made as procedures only? or is there a way to do this efficiently with Linq2Entities that i am missing?
If you have the primary key values then you can use the other features of the Context by creating the objects manually, setting their key(s), and attaching them to the context and setting their state to delete.
var ids = new List<Guid>();
foreach (var id in ids)
{
Employee employee = new Employee();
employee.Id = id;
entityEntry = context.Entry(employee);
entityEntry.State = EntityState.Deleted;
}
context.SaveChanges();

C# Entity Framework Linq Query not recognizing new changes

I'm using C#, .NET (4.0) and Entity Framework to connect to SQL CE 4.0.
I query some objects with specific properties, but the query returns only objects that meet search criteria only if that data was already saved to database, which is not that problematic, bigger problem is that if data is changed, but not yet saved to database it will still meet search criteria.
Example:
var query = from location in mainDBContext.Locations
where location.InUse == true
select location;
This query returns also objects where location.InUse = false if InUse was true when loaded from DB and then changed later on in code.
This is screen capture from one of the query results objects.
I really don't understand why it does this. I would understand if this query would always query database and I would get the older version of this object (thus InUse would be true).
Thank you for your time and answers.
That is how EF works internally.
Every entity uniquely identified by its key can be tracked by the context only once - that is called identity map. So it doesn't matter how many times did you execute the query. If the query is returning tracked entities and if it is repeatedly executed on the same context instance it will always return the same instance.
If the instance was modified in the application but not saved to the database your query will be executed on the database where persisted state will be evaluated but materialization process will by default use the current data from the application instead of data retrieved from the database. You can force the query to return state from the database (by setting mainDBContext.Locations.MergeOption = MergeOption.OverwriteChagens) but because of identity map your current modifications will be lost.
I'm not really sure what exactly your problem is, but I think you have to know this:
That kind of query always return data that is submitted into DB. When you change some entities in your code but they are not submitted into database the LINQ query will query the data from database, without your in-code changes.
LINQ queries use Deferred Execution, so your 'query' variable is not a list of results, it's just a query definition that is evaluated each time results are needed. You should add .ToList() to evaluate that query and get a list of results in that certain line of code.
An example for .ToList():
var query = (from location in mainDBContext.Locations
where location.InUse == true
select location).ToList();
I just ran into the same thing myself. It's a bit messy, but another option is to examine the Local cache. You can do this, for example:
var query = from location in mainDBContext.Locations.Local
where location.InUse == true
select location;
This will only use the local cache not saved to the database. A combination of local and database queries should enable you to get what you want.

CRM 2011: Limitation of query expression?

I believe the answer to this question may be to use Linq to Sql, but wanted to see if this is something which is possible using QueryExpressions:-
I create a query expression which queries against Entity A, it also links to Entity B (via LinkEntity) and imposes additional criteria. It is possible to retrieve columns from Entity B by adding the appropriate attribute names. However, it will only retrieve the linked entity (inner join).
Is it possible using QueryExpression to retrieve all related records (and required columns) from Entity B related to Entity A (e.g. all cases associated with contact where contact passes specified criteria). Normally I would consider inverting the query and searching for Entity B relatig to Entity A with the appropriate LinkEntity Conditions, but there are a number of linked entities which I would like to retrieve for the same contact query.
So I'm left with some options:-
(1) Perform a second query (not ideal when iterating over a large number of results from the initial query),
(2) Perform a query using Linq to CRM on the filtered views,
(3) A different method entirely?
Any thoughts would be appreciated.
EDIT:
I ended up using Linq-to-Sql to complete this task and the code used is similar to that below (albeit with a few more joins for the actual query!):-
var dataCollection = (from eA in xrmServiceContext.EntityASet
join eB in xrmServiceContext.EntityBSet on new EntityReference(EntityA.EntityLogicalName, eA.Id) equals (EntityReference)eB.EntityBLookupToEntityA
select new
{
Id = eA.Id,
EntityBInterestingAttribute = eB.InterestingAttributeName
}
So this will bring back a row per Entity A, per Entity B. To make things easier I then defined a custom class "MyEntityAClass" which had properties which were Lists so I could return one object for filling of GridView etc. This is more to do with the processing of these results though so I haven't posted that code here.
I hope that makes sense. Essentially, it is getting the multiple rows per record a la SQL which makes this method work.
QueryExpression can only return fields from one type of entity, the one specified in QueryExpression.EntityName.
You can use FetchXML which allows you to also get the fields of any link entities, which would be an option 3 for you, unfortunately it returns the data as XML which you would then have to parse yourself.
It might be quicker to run the FetchXML, but it will take longet to write and test, and its not the easiest thing to maintain either.
Sample Code, this gets the first 101 of all Cases that are active for all accounts that are active
string fetch = "<fetch count='101' mapping='logical'><entity name='account'><filter type='and'><condition attribute='statecode' operator='eq' value='1'/></filter><link-entity name='incident' from='customerid' to='accountid'><all-attributes/><filter type='and'><condition attribute='statecode' operator='eq' value='1'/></filter></link-entity></entity></fetch>";
string data = yourCrmServiceObject.Fetch(fetch);

Categories