Advanced database query - c#

I have this method:
public async Task<ProductReport<ProductPrice>> GetCurrentProductsReport()
{
var query = (DataServiceQuery<ProductPrice>)(
from p in this.entities.Products
where !p.Discontinued
orderby p.ProductName
select new ProductPrice
{
Name = p.ProductName,
Price = p.UnitPrice ?? 0,
});
var result = await Task<IEnumerable<ProductPrice>>.Factory.FromAsync(query.BeginExecute(null, null), (ar) =>
{
return query.EndExecute(ar);
});
return new ProductReport<ProductPrice>(result);
}
This method returns an incomplete list of products. The number of items in the list is limited by the number of items that the service returns in one request.
I need to get all data.
I know I can use the GetContinuation() method, but I can't use it in this situation.
Maybe someone knows how to solve this problem?

I need to get all data.
Create a stored procedure and extract the full total data rows/columns as needed.

Related

MVC 5 - Why is my linq code selecting an entire query instead of a single value?

Here is an example of what some locations look like in my database:
ID, DepartmentId, LocationName
8,2,Main Warehouse
12,2, Filter Cellar
When I use the following code, it grabs the entire query and puts it as the value for my HTML dropdown list.
public ActionResult GetLocations(int id)
{
List<SelectListItem> locations = new List<SelectListItem>();
//based on the input coming to this method ( product id)
var incident = new AccidentSupervisorViewModel();
incident.Locations = DB.Locations.ToList().Select(i => new SelectListItem
{
Text = i.LocationName,
Value = i.DepartmentId.ToString()
}
).Where(i => i.Value == id.ToString());
var departmentId = from loc in DB.Locations where loc.DepartmentId == id select loc.DepartmentId;
for (var x = 0; x < incident.Locations.Count(); x++) {
locations.Add(new SelectListItem {
Text = incident.Locations.ElementAt(x).Text,
Value = departmentId.ToString()
});
}
return Json(locations,JsonRequestBehavior.AllowGet);
}
This is most likely happening because I have a syntax error, but I haven't used linq much for queries so any help is appreciated.
It appears you've not 'done' anything with the IQueryable<T> that is generated by Linq. Linq generates the query but doesn't do anything with it until the IQueryable<T> or other IEnumerable is iterated over. See Deferred Execution and Classification of Standard Query Operators by Manner of Execution.
In your case, since you're looking for a single value, you'll need to pop in the following line after you first declare departmentId:
var department = departmentId.FirstOrDefault();
This will pop out the first or default value from the IQueryable<T> you made.

Breeze Framework - how to do an inline Subtable Count query

I have a table Supplier, with subtable 1 to many Product. I would like to replicate the results of this query in Breeaze:
SELECT *,
(select count(*) from Product where Supplier.id = Product.SupplierId) ProductCount
FROM Supplier
Basically, I'd like to have an output of the Supplier data columns, with an appended column of that supplier's product count.
I currently have this query in Breeze which gives me suppliers, but I don't see a way to add the count column to the results. I already have a field in the Entity ProductCount in place and NonMappable to contain it:
var query = _repository.Suppliers.AsQueryable();
if (supplierIds.Length > 0)
{
query = query.Where(supplier => supplierIds.Contains(supplier.Id));
var result = query.ToList();
}
return query;
What am I missing? Is there a way to do this in Breeze or no?
Thanks for the assistance!
Have a look at the inlineCount property in Breeze query structure :
successFunction([data]) {
....
}
you can get :
results : fields of the query (array)
inlineCount :
Only available if 'inlineCount(true)' was applied to the query. Returns the count of items that would have been returned by the query before applying any skip or take operators, but after any filter/where predicates would have been applied.
For instance :
var query = new EntityQuery("Clients")
.where("ClientName", "startsWith", "B")
.take(20)
.orderBy("ClientName")
.inlineCount(true);
The result
query.execute().then( function(data) {
data.results
data.inlineCount
}
The data.inlineCount column will return 12 if your query contains 12 clients name started with "B" even if the total records returned may totalized 20.
If you already have a ProductCount property on your Supplier entity, you just need to return it from the server. If ProductCount is on the server-side entity, you can populate the property on the server and the client side will just work:
[HttpGet]
public IQueryable<Supplier> SuppliersWithProductCount()
{
var query = _repository.Suppliers.AsQueryable();
// ...add server-side params to the query, if desired...
// Get objects with the supplier and the count
var list = query.Select(s => new { Supplier = s, Count = s.Products.Count }).ToList();
// Set the count on the Supplier
list.ForEach(o => o.Supplier.ProductCount = o.Count);
// Extract the Suppliers
var suppliers = list.Select(o => o.Supplier);
return suppliers.AsQueryable();
}
On the other hand, if the ProductCount property only exists on the client, you will need to pass it to the client separately, and set the property on the client-side entities in your query result handler.
On the server:
[HttpGet]
public IQueryable<Object> SuppliersWithProductCount()
{
var query = ContextProvider.Context.Suppliers.AsQueryable();
// ...add server-side params to the query, if desired...
// Get objects with the supplier and the count
return query.Select(s => new { Supplier = s, Count = s.Products.Count });
}
On the client:
EntityQuery.from("SuppliersWithProductCount")
.using(myEntityManager).execute()
.then(function (data) {
// results are { Supplier, Count } objects
var results = data.results;
var suppliers = [];
results.forEach(function (r) {
r.Supplier.ProductCount = r.Count;
suppliers.push(r.Supplier);
});
return suppliers;
});

Linq select from CRM public view

I have searching for a while now, but couldn't find how to query from public view. For example, I have predefined public view called Active Accounts and I want data from it.
So far I only know this way, but that not include any views:
using (var xrm = new XrmServiceContext("Xrm"))
{
var activeAccounts = from a in xrm.AccountSet
where a.StateCode == 0
select new { a.Id, a.Name };
// TODO ...
}
But I would like to do it like this (not working, ActiveAccountsView not exist, it's pseudo):
using (var xrm = new XrmServiceContext("Xrm"))
{
var activeAccounts = from a in xrm.ActiveAccountsView
select new { a.Id, a.Name };
// TODO ...
}
Is this even possible?
The query definitions of public views are stored in the savedquery entity, that can be queried using common techniques.
Out-of-the-box views are stored with a fixed ID, so querying Active Accounts on the OrganizationServiceContext object could be done in the following way:
private static IEnumerable<Entity> GetActiveAccounts(OrganizationServiceContext serviceContext)
{
string fetchXml = serviceContext
.CreateQuery("savedquery")
.Where(sq =>
sq.GetAttributeValue<Guid>("savedqueryid") == new Guid("00000000-0000-0000-00AA-000010001002"))
.Select(sq => sq.GetAttributeValue<string>("fetchxml"))
.First();
var request = new RetrieveMultipleRequest
{
Query = new FetchExpression(fetchXml)
};
var response = (RetrieveMultipleResponse) serviceContext.Execute(request);
return response.EntityCollection.Entities;
}
It is not possible to use LINQ here. LINQ relies on the QueryExpression class, but does not implement all its capabilities (OUTER JOIN is a painful omission for example). So, while it is possible to convert a LINQ query to a QueryExpression, the other way around is not.
Paging can be applied by editing the Fetch XML string, but if that is too much hassle, you can also consider to convert the Fetch XML to a QueryExpression and apply paging on that object:
private IEnumerable<Entity> GetActiveAccounts(int pageNumber)
{
string fetchXml = _serviceContext
.CreateQuery("savedquery")
.Where(sq =>
sq.GetAttributeValue<Guid>("savedqueryid") == new Guid("00000000-0000-0000-00AA-000010001002"))
.Select(sq => sq.GetAttributeValue<string>("fetchxml"))
.First();
var conversionRequest = new FetchXmlToQueryExpressionRequest
{
FetchXml = fetchXml
};
var response = (FetchXmlToQueryExpressionResponse)_serviceContext.Execute(conversionRequest);
response.Query.PageInfo = new PagingInfo { Count = 1, PageNumber = pageNumber };
var queryRequest = new RetrieveMultipleRequest
{
Query = response.Query
};
var result = (RetrieveMultipleResponse) _serviceContext.Execute(queryRequest);
return result.EntityCollection.Entities;
}
Additional advantage of the QueryExpression vs. Fetch XML is that it is processed in a bit more efficient way.
The very same can be done with user defined views; these views are stored in the userquery entity. The only difference here is you cannot rely on a fixed view ID. Instead you would need to filter your query on querytype, name, returnedtypecode, ownerid and/or other criteria.
Dynamics CRM also has an OrganizationRequest that allows you to execute the savedquery immediately. However, it returns its result as a resultset XML string, so you would still need to deserialize the response. (A nice example can be found here.) Also, I am not sure if it is possible to limit the result set to a specific page when using the ExecuteByIdSavedQueryRequest:
var request = new ExecuteByIdSavedQueryRequest
{
EntityId = new Guid("00000000-0000-0000-00AA-000010001002")
};
var response = (ExecuteByIdSavedQueryResponse)serviceContext.Execute(request);
string resultset = response.String;

Why is LINQ OrderByDescending not working with a view composed of a union between two tables?

I have a view in my SQL Server database that is a UNION ALL of two tables. When I retrieve all the rows from the view for a specific member, this is my call.
public IEnumerable<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var query = Manager.MemberTransactions
.Where(m => m.SocSecNo == socSecNo)
.OrderByDescending(m => m.TranDate);
var results = query.Execute();
return results;
}
I call the Get method from my code and assign the returned collection to the datasource propery of a grid. The rows are not displayed as per the order by statement in the Get method. they are displayed in random order.
I am forced to do this to get the rows to display properly.
IEnumerable<MemberTransaction> transactions = FetchMemberTransactions(currentMember.SocSecNo);
MemberTransactionBS.DataSource = transactions.OrderByDescending(t => t.TranDate);
MemberTransactionsGrid.Refresh();
public IEnumerable<MemberTransaction> FetchMemberTransactions(string socSecNo)
{
var transactions = Repository.GetMemberTransactions(socSecNo);
return transactions;
}
Is there an issue with returning rows from a union? Why is the OrderByDescending not working as expected?
If the order is being returned correctly from the database (test this first like other answers sugest) try returning an IOrderedEnumerable<MemberTransaction> instead of IEnumerable<MemberTransaction>.
You said First Way doesn't work but it worked on me! So try Second Way please.
// First Way
public List<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var orderedListOfData = Manager.MemberTransactions
.Where(m => m.SocSecNo == socSecNo)
.OrderByDescending(m => m.TranDate).ToList();
return orderedListOfData;
}
// Second Way
public List<MemberTransaction> GetMemberTransactions(string socSecNo)
{
var orderedListOfData = (from m in Manager.MemberTransactions
where m.SocSecNo == socSecNo
orderby m.TranDate descending
select m).ToList();
return orderedListOfData;
}

LINQ query with SELECT and two GROUP-BY condition

What's the equivalent LINQ instruction for a Datatable of the following SQL query:
SELECT code_direction, count(TP) AS CN
FROM table1
WHERE cod_time = 'A011'
GROUP BY TP,code_direction;
and how to get the result into a new datatable?
I tried to convert it but I there're some errors. Someone could take a look on this:
var query = from t in table1.AsEnumerable()
group t by new { t.TP, t.code_direction }
into grp
select new
{
grp.Key.code_direction,
CN = grp.Count(t.TP)
};
foreach (var x in query)
{
Console.Write(x.code_direction);
Console.Write(x.CN);
}
As far as your first question goes. The LINQ equivalent of the SQL query is:
var query = from t in table1.AsEnumerable()
where t.cod_time == "A011"
group t by new { t.TP, t.code_direction }
into grp
select new
{
grp.Key.code_direction,
CN = grp.Count()
};
Note that you don't have to pass any argument to grp.Count(). (For the obvious reason that in SQL COUNT(TP) is the same as COUNT(*), i.e. just count the number of rows. The story would be different if you'd use COUNT(DISTINCT TP) or similar.)
As far as the second question goes, if your query just returned an IEnumerable<T> where T is DataRow (i.e. a query like table1.AsEnumerable().Where(r => r.cod_time == "A011")) then you could just the DataTableExtensions.CopyToDataTable extension method. As your query returns an anonymous type however, you will have to follow these instructions found on MSDN.
I Have been using LINQ to work on a JSON object returned from a remote sharepoint web service. I have posted this because most of the answers I found online were slightly different from what I needed.
a json list of daily activities is returned from a remote sharepoint list & is then summarised using LINQ
The simplified version of a custom object definition is shown below( & which is defined in the models area of an MVC application)
public class MyCustomObjectList
{
public string eventdate { get; set; }
public string userid { get; set; }
public string action { get; set; }
}
The JSON object is serialised into a MyCustomObjectList array.
var customobject = serializer.Deserialize<MyCustomObjectList>(jsonobject);
I wanted to work out how many actions of each type happened on a given day. NB eventdate is stored as a string in format yyyy-mm-dd hh:MM:ss. This was to simplify conversions between c#, JSON & Jquery ( where required I create DateTime objects elsewhere in the code using the
eventdate.
Some will argue this is inefficient, but I prefer to split processes into a sequential set of really simple operations, for the sake of easier debugging & to help other people follow my code. Thats why there are 2 Linq queries .
querya strips out the time component from the eventdate This ensures our later grouping happens by day, & not by second. To be doubly sure that there is no caching, I create it in a new field called actionday. I also rename action to activity, because intellisense was getting confused!! The other columns are copied as is.
var querya =
from c in customobject.rows
select new { actionday = c.eventdate.Substring(0, 10), activity = c.action, c.userid,
c.eventdate };
/* queryb produces a grouped count of querya, grouped on actionday & activity, creating new columns actionkey,ActionCount,Dte,action & DetailList ( which is a summary for debugging purposes)
*/
var queryb=
from p in querya group p by new { p.actionday, p.activity} into idGroup
actionkey = idGroup.Key,
ActionCount = idGroup.Count(),
Dte = idGroup.Key.actionday,
action = idGroup.Key.activity,
DetailList = idGroup
};
Here’s a version that sumarises by 3 columns
var queryc = from p in querya
group p by new { p.actionday, p.userid, p.activity} into idGroup
select new
{
actionday = idGroup.Key,
ActionCount = idGroup.Count(),
userid = idGroup.Key.userid,
Dte = idGroup.Key.actionday,
action = idGroup.Key.activity,
DetailList = idGroup
};

Categories