I have the following scenario.
I have one table in the database A that contains a lot of entries. This table is lightweight and only have a bit of data for each entry.
Another table B has a many to one relationship with A, and can contain lots of data.
I have a client and a server in my application that communicates using WCF.
My problem is that when the client calls a method on the server that should return all the A's, I get much more data than I need to. On the server I basically have a single line of code:
return entityContext.A.ToList();
My problem is that on the client, if I debug and inspect the returned collection, each element has the property B populated with all the data from the expensive table.
I only needed the basic data from the A table to show a list on the client, but ended up sending a ton of data over the wire.
So the question is, how can I make the server ignore the B table when I fetch the data to send to the client. Basically, I need something like the oposite of Include.
You need to turn off lazy loading. It can be done either through designer or in code by calling:
entityContext.ContextOptions.LazyLoadingEnabled = false;
Related
I want to see the difference of Delivery Class 'A' and 'C'. C for data entered only by the customer, but how can I see it on the code?
I created two tables of type 'A' and 'C'. I add data with ABAP code. I thought I couldn't add data to the table I created with C, but they both work the same.
For A Type:
DATA wa_ogr LIKE ZSGT_DELIVCLS2.
wa_ogr-ogrenci_no = 1.
wa_ogr-ogrenci_adi = 'Seher'.
INSERT ZSGT_DELIVCLS2 FROM wa_ogr.
For C Type:
DATA wa_ogr LIKE ZSGT_DELIVERYCLS.
wa_ogr2-ogrenci_no = 1.
wa_ogr2-ogrenci_adi = 'Seher'.
INSERT ZSGT_DELIVERYCLS FROM wa_ogr2.
Datas get trouble-free when I check with debugging.
Is there a live demo where I can see the working logic of C? Can you describe Delivery Class C better?
Tables with delivery class C are not "customer" tables, they are "customizing" tables. "Customizing" is SAPspeak for configuration settings. They are supposed to contain system-wide or client-wide settings which are supposed to be set in the development system and then get transported into the production system using a customizing transport. But if that's actually the case or not depends on what setting you choose when generating a maintenance dialog with transaction SE54. It's possible to have customizing tables which are supposed to be set in the production system directly without a transport request.
Tables with delivery class A are supposed to contain application data. Data which is created and updated by applications as part of their every day routine business processes. There should usually be no reason to transport that data (although you can do that by manually adding the table name and keys to a transport request). Those applications can be SAP standard applications, customer-developed applications or both.
There is also the delivery class L which is supposed to be used for short-living temporary data as well as the classes G, E, S and W which should only be used by SAP on tables they created.
But from the perspective of an ABAP program, there is no difference between these settings. Any ABAP keywords which read or write database tables work the same way regardless of delivery class.
But there are some SAP standard tools which treat these tables differently. One important one are client copies:
Data in delivery class C tables will always be copied.
Data in delivery class A tables is only copied when desired (it's a setting in the copy profile). You switch it off to create an empty client with all the settings of an existing client or to synchronize customizing settings between two existing clients without overwriting any of the application data. You switch it on if you want to create a copy of your application data, for example if you want a backup or want to perform a destructive test on real data.
Data in delivery class L tables doesn't get copied.
For more information on delivery classes, check the documentation.
Paging using LINQ can be easily done using the Skip() and Take() extensions.
I have been scratching my head for quite some time now, trying to find a good way to perform paging of a dynamic collection of entities - i.e. a collection that can change between two sequential queries.
Assume a query that without paging will return 20 objects of type MyEntity.
The following two lines will trigger two DB hits that will populate results1 and results2 with all of the objects in the dataset.
List<MyEntity> results1 = query.Take(10).ToList();
List<MyEntity> results2 = query.Skip(10).Take(10).ToList();
Now let's assume the data is dynamic, and that a new MyEntity is inserted into the DB between the two queries, in such a way that the original query will place the new entity in the first page.
In that case, results2 list will contain an entity that also exists in results1,
causing duplication of results being sent to the consumer of the query.
Assuming a record from the first page was deleted, it will result missing a record that should have originally appear on results2.
I thought about adding a Where() clause to the query that verify that the records where not retrieved on a previous page, but it seems like the wrong way to go, and it won't help with the second scenario.
I thought about keeping a record of query executions' timestamps, attaching a LastUpdatedTimestamp to each entity and filtering entities that were changed after the previous page request. That direction will fail on the third page afterwards...
How is this normally done?
Is there a way to run a query against an old snapshot of the DB?
Edit:
The background is an Asp.NET MVC WebApi service that responds to a simple GET request to retrieve the list of entities. The client retrieves a page of entities, and presents them to the user. When scrolled down, the client sends another request to the service, to retrieve another page of entities, which should be added to the first page which is already presented to the user.
One way to solve this is to keep a TimeStamp of the first query and exclude any results that have been added after that time. However this solution puts the data into a "stale" state, i.e the data is fixed at a certain point in time, which is usually a bad idea unless you have a very good reason to do it.
Another way of doing this (again depending on your application) would be to store the list of all objects in memory and then only display a certain number of results at one time.
List<Entity> _list;
public class SomeCtor()
{
_list = _db.Entities.ToList();
}
public List<Entity> GetFirst10
{
get
{
return _list.Take(10);
}
}
public List<Entity> GetSecond10
{
get
{
return _list.Skip(10).Take(10);
}
}
I've got a table "Events" with a linked table "Registrations", and I want to create an OData service that returns records from the Events table, plus the number of registrations for each event. The data will be consumed client-side in JavaScript, so I want to keep the size of the returned data down and not include all linked registration records completely.
For example:
ID Title Date Regs
1 Breakfast 01.01.01 12:00 4
2 Party 01.01.01 20:00 20
I'm building the service with ASP.NET MVC4. The tables are in an MSSQL database. I am really just getting started with OData and LINQ.
I tried using the WebAPI OData system first (using classes of EntitySetController) but was getting cryptic server errors as soon as I included the Registrations table in the entity set. ("The complex type 'Models.Registration' refers to the entity type 'Models.Event' through the property 'Event'.")
I had more success building a WCF OData system, and can request event information and information on related registrations.
However, I have no clue how to include the aggregate count information in the event result set. Do I need to create a custom entity set that will be the source for the OData service? I probably included too litte information here for finding a solution, but I don't really know where to look. Can somebody help me?
If you're willing to make an extra request per Event, you could query http://.../YourService.svc/Events(<key>)/Registrations/$count (or http://.../YourService.svc/Events(<key>)/$links/Registrations?$inlinecount=allpages if you're also using the links to the Registration entities).
Examples of both of these approaches on a public service:
http://services.odata.org/V3/OData/OData.svc/Suppliers(0)/Products/$count
http://services.odata.org/V3/OData/OData.svc/Suppliers(0)/$links/Products?$inlinecount=allpages&$format=json
I'm guessing that you'd prefer this information to come bundled together with the rest of the Events response though. It's not ideal, but you could issue a query along these lines:
http://services.odata.org/V3/OData/OData.svc/Suppliers?$format=json&$expand=Products&$select=Products/ID,*
I'm expanding Products (analogous to your Registrations) and selecting Products/ID in order to force the response to include an array that is the same size as the nested Products collection. I don't care about ID -- I just chose a piece of data that would be small. With this JSON response, your javascript client can get the length of the Products array and use that as the number of Products that are linked to the given Supplier.
(Note: to have your service support $select queries using WCF Data Services, you'll need to include this line when you initialize the service: config.DataServiceBehavior.AcceptProjectionRequests = true;)
Edit to add: The approach using $expand and $select won't be guaranteed to give you the correct count if your server does server-driving paging. In general, there isn't a simple single-response way to do what you're asking for in OData v3, but in OData v4, this will be possible with the new expand/select syntax.
i'm using oData v4 and i used this syntax :
var url = '.../odata/clients?$expand=Orders($count=true)';
// ...
a field called Orders#odata.count has been added to the response entity which contains the correct count.
and now to access the JSON property containing a dash you have to do it like this :
var ordersCount = response.value['Orders#odata.count'];
hope this helps.
Can you edit your Event model and add a RegistrationCount property? That'd be the simplest way I think
What I ended up doing was actually very simple; I created a View in SQL Server that returns the table including the registration counts. Never thought about using a view, since I've never used them before...
I used this to get the child count without returning the entities:
/Parents$expand=Children($count=true;$top=0)
I have an object graph consisting of a base employee object, and a set of related message objects.
I am able to return the employee objects based on search criteria on the employee properties (eg team) etc. However, if I expand on the messages, I get the full collection of messages back. I would like to be able to either take the top n messages (i.e. restrict to 10 most recent) or ideally use a date range on the message objects to limit how many are brought back.
So far I have not been able to figure out a way of doing this:
I get an error if I attempt to filter on properties on the message (&$filter=employee/message/StartDate gives an error ">No property 'StartDate' exists in type 'System.Data.Objects.DataClasses.EntityCollection`1).
Attempting to use Top on the message related object doesn't work either.
I have also tried using a WebGet extension that takes a string list of employee IDs. That works until the list gets too long, and then fails due to the URL getting too long (it might be possible to setup a paging mechanism on this approach)...
Unfortunately the UI control I am using requires the data to be in a fairly specific hierarchical shape, so I can't easily come at this from starting on the message side and working backwards.
Outside of making multiple calls does anyone know of a method to accomplish this with wcf data services?
Thanks!
M.
Looks like the only real way of doing this is in fact to reverse the direction of the query.
So instead of starting from the Employee, I go from the message side. You can filter back on the employee properties, and restrict on the Messages collection. Its not ideal, as it means iterating the collection on return to re-center it on the employee for what I am attempting to do, but it will work. The async nature of silverlight and rich client at least means while an extra iteration is required, it still appears to be reasonably fast.
Another interesting thing to note: the current version of odata/wcf data services does not support querying on properties of inherited classes, so I had to move the start/end date properties up to the base class in order to be able to restrict my search on them.
http://Site/Service.svc/Messages()?&$filter=Employee/OfficeName eq 'Toronto' and (year(StartDate) eq 2010 and month(StartDate) ge 9 )
I'm using Silverlight 4.0 (so I need to make the call async and can't use EF directly) with a WCF Data Service and EF 4 to model the database.I want to make one call and have several levels of properties populated.
Say I have the following setup (but this could go deeper):
Accounts
-- has zero or more Customers (and other properties)
-- Customer has zero or more Addresses (and other properties)
I want to bring back 1 payload where Accounts, Customers, and Addresses are all eager loading and included in that one payload.
I want to get : Accounts.Expand("Customers").Where(a => a.Id == 1); This returns the payload with the account and customer populated. How do I include the Addresses in the same call?
Just add Expand("Customers/Addresses"), you can add more of these, although there's a limit usually on the server. Something like 10 expanded entities should work, more might be problematic.