Unable to get a total count of items in the model in the ASP.NET MVC view - vb.net

I am using the following code to render a pager:
#Html.BootstrapPager(Request.QueryString("Page"), Function(index) Url.Action("Index", "Posts", New With {.page = index}), 14000, System.Web.Configuration.WebConfigurationManager.AppSettings("PageSize"), 15)
My problem is that If I use Model.Count in place of the 14000 then I only get 1 page of records since I am using skip and take in the repository to pull only the need records. How can i in the view access the total number of published records so that I don't have to hard code the value into the view right now?
The original pager code is here. I converted it to VBNET am using it. It works fine if the record count is hardcoded.
This is the repo:
Dim posts As IEnumerable(Of PostSummaryDTO)
Using db As BetterBlogContext = New BetterBlogContext
posts = db.be_Posts.OrderByDescending(Function(x) x.DateCreated).Select(Function(s) New PostSummaryDTO With {.Id = s.PostRowID, .PostDateCreated = s.DateCreated, .PostSummary = s.Description, .PostTitle = s.Title, .IsPublished = s.IsPublished}).Skip((Page - 1) * PageSize).Take(PageSize).ToList()
Return posts.ToList
End Using

You need two different methods in the lower layer - one to get the total count and one to get the desired page - and then call them both from your controller, passing both results in the model to the view. As such, the model cannot be a collection of records; it must be an object with a property for a collection of records and a property for the count. Either that or use the ViewBag to pass the count.
What we do in my office is have a service layer to contain the business logic and repository to handle the data access. There is a single method in the repository to return an IQueryable that provides access to all the records for a particular table. There are then one or more methods in the service that call that repository method and use it in different ways. In this case, there might be a GetTotalCount method and a GetPage method in the service. Both would call the same repository method to get the same IQueryable and then the first method would call Count on the result while the second method would call Skip and Take. As Skip and Take don't force execution of the query, you'd also call ToArray or the like in that second method. The service might also have a GetRecord method that you would pass an ID and call FirstOrDefault inside to get a single record with a matching ID. You can roll the service and repository into a single class if you want but I'd recommend separating the business logic from the data access.

Related

Titanium access a model from other controller

I learned that is this how to access a model from other controller,
var book = Alloy.Models.instance('book');
And this is how to access a property of a model,
var name = book.get('name');
However in the console,the name logs [INFO] : { } , meaning this doesn't get its property value, and ofcourse the model has already a data saved on it. Thanks for your help!
You may have to fetch the collection first:
var books = Alloy.Collections.book;
books.fetch();
This will load all the models from the collection so you can use them.
although the above works, there are a few addtional points here.
the call is asynchronous in most cases so you should be getting the model in a callback which is not presented in the code above.
I dont know if fetching the collection everytime you want a model is the correct approach either? If the collection already exists you just need to get the model from the collection just using the id.
depending on the exact use case, you might just want to pass the model as a parameter from one controller to the next

Expand() method doesn't bind all Data to the object

I'm trying to query a WCF Data Service with oData. Everything works fine, but in a many to many relation the expand Function doesn't work. The Relation is: Product 1-* ProductOrder *-1 Order Here is my code to query the service:
var queryProductOrder = (DataServiceQuery<ProductOrder>)SessionHelper.context.ProductOrder.Expand(x=>x.Product);
var allProductOrders = await queryProductOrder.ExecuteAsync();
If I run this in debug mode and check the allProductOrder Object, there is no Product. The interesting fact is, that when I check the generated OData Query and run it over the browser, the Product gets expanded.
The query looks like this:
http://localhost:10000/ProductOrder()?$expand=Product
And the JSON-Result is expanded:
{"odata.metadata":"http://localhost:10000/$metadata#ProductOrder","value":[{"Product":{"id":1,"Name":"Die Sims","Tax_fk":1,"Price":"44.99","Description":"Lebenssimulation","Stock":"99.00","TotalOrder":"0.00","ProductUnit_fk":1,"Barcode":"121212121","MainImage_fk":null,"Tenant_fk":1,"PurchasePrice":null},"id":1,"Product_fk":1,"Order_fk":1,"Tenant_fk":1,"Amount":"10"}]}
Also confusing is the fact, that on other many to many relations the expand method works like it should.
Why it doesn't expand the allProductOrders Object? Why is the allProductOrders.First().Product object null but the generated OData query returns the Expanded data?

Native Query Mapping on the fly openJPA

I am wondering if it is possible to map a named native query on the fly instead of getting back a list of Object[] and then looping through and setting up the object that way. I have a call which I know ill return a massive data set and I want to be able to map it right to my entity. Can I do that or will I have to continue looping through the result set.
Here is what I am doing now...
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5)).getResultList();
That is my entity, the List (my entity is the provider). Normally I would just return a List<Object[]>
and then I would loop through that to get back all the objects and set them up as new providers and add them to a list....
//List<Provider> provList = new ArrayList<Provider>();
/*for(Object[] obj: ObjList)
{
provList.add(this.GetProviderFromObj(obj));
}*/
As you can see I commented that section of the code out to try this out. I know you can map named native queries if you put your native query in the entity itself and then call it via createNamedQuery. I would do it that way, but I need to use the IN oracle keyword because I have a list of ID's that I want to check against. It is not just one that is needed. And as we all know, native queruies don't handle the in keyword to well. Any advice?
Sigh, If only the IN keyword was supported well for NamedNativeQueries.
Assuming that Provider is configured as a JPA entity, you should be able to specify the class as the second parameter to your createNativeQuery call. For example:
List<Provider> ObjList = (List<Provider>) emf.createNativeQuery(assembleQuery(organizationIDs, 5), Provider.class).getResultList();
According to the documentation, "At a minimum, your SQL must select the class' primary key columns, discriminator column (if mapped), and version column (also if mapped)."
See the OpenJPA documentation for more details.

Retrieving data from WCF service

Let's say I have database with two tables - Groups and Items.
Table Groups has only two columns: Id and Name.
Table Items has three columns: Id, GroupId and Name.
As you can see, there is one-to-many relation between Groups and Items.
I'm trying to build a web service using WCF and LINQ. I've added new LINQ to SQL classes file, and I've imported these two tables. Visual Studio has automatically generated proper classes for me.
After that, I've create simple client for the service, just to check if everything is working. After I call GetAllGroups() method, I get all groups from Groups table. But their property Items is always null.
So my question is - is there a way to force WCF to return whole class (whole Group class and all Items that belong to it)? Or is this the way it should behave?
EDIT: This is function inside WCF Service that returns all Groups:
public List<Group> GetAllGroups()
{
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
I've checked while debugging and every Group object inside GetAllGroups() function has it's items, but after client receives them - every Items property is set to null.
Most likely, you're experiencing the default "lazy-loading" behavior of Linq-to-SQL. When you debug and look at the .Items collection - that causes the items to be loaded. This doesn't happen however when your service code runs normally.
You can however enforce "eager-loading" of those items - try something like this:
(see Using DataLoadOptions to Control Deferred Loading or LINQ to SQL, Lazy Loading and Prefetching for more details)
public List<Group> GetAllGroups()
{
// this line should really be where you *instantiate* your "db" context!
db.DeferredLoadingEnabled = false;
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Group>(g => g.Items);
db.LoadOptions = dlo;
List<Group> groups = (from r in db.Groups select r).ToList();
return groups;
}
Do you get the Items collection populated now, when you call your service?

Overload of actions in the controller

Is it possible to do an overload of the actions in the controller? I haven't found any info about it and when I tried, I got this error:
The current request for action 'Create' on controller type 'InterviewController' is >ambiguous between the following action methods:
System.Web.Mvc.ViewResult Create() on type >MvcApplication4.MvcApplication4.InterviewController
System.Web.Mvc.ViewResult Create(Int32) on type >MvcApplication4.MvcApplication4.InterviewController
I've tried to do this on another way and I also get a new error that I can't fix. In fact, I created a new action (called create_client instead of create)
I need 2 ways of creating an "opportunite".
I just call the action, and I receive an empty formular in which I just have to insert data.
From a client's page, I must create an "opportunite" with the client that's already completed when the form is displayed to the user. (there is a need of productivity, the user must perform actions as fast as possible).
In the table "opportunite", I've got a column called "FK_opp_client", which is equal to the column "idClient" from the client's table.
I don't get how I can do the second way.
I've created a new action in the controller.
'
' GET: /Opportunite/Create_client
Function Create_client(idclient) As ViewResult
'Dim FK_Client = (From e In db.client
'Where(e.idClient = idclient)
' Select e.nomCompteClient).ToString()
'ViewBag.FK_client = New SelectList(db.client, "idClient", "nomCompteClient", idclient)
Dim opportunite As opportunite = db.opportunite.Single(Function(o) o.idOpportunite = 5)
opportunite.FK_Client = idclient
ViewBag.FK_Client = New SelectList(db.client, "idClient", "nomCompteClient", opportunite.FK_Client)
Return View(opportunite)
End Function
I've tried a few things to get what I wanted, the last one was to copy what was done in the "Edit" action, but for an empty rank. (so I created an empty rank in my DB). I don't think it was a good idea (imagine someone wants to update the DB where idOpportunite = 5...)
Any better ideas?
If you want to keep those two methods under the same name, you will have to implement an ActionSelectionAttribute to decorate them, or use them with different verbs (for example POST and PUT). Please read more details on action method selection process here (old but still true).
Different approach might be making your parameter optional and make action to check if it has been passed or not (through nullable type).