I'm creating a small forum for my CMS and I'm using subsonic 2.2 as my DAL.
I'm loading my theads like this:
DAL.ForumThread item = DAL.ForumThread.FetchByID(id);
In my database my ForumPosts table looks like this:
ForumPostID | ThreadID | Description | UserID | CreatedOn| etc
So now when I have my DAL.ForumThread item I can load the connected post collection by using:
item.ForumPosts();
This all works great, but the problem is that I'm using serverside paging and want to add some additional select parameters too like showing only active records.
Is this even possible when using SubSonic 2.2 ? The workaround I have now is just creating a new SubSonic.Query and select the posts by threadid and there I can set pageindex and pagesize without problems but I think this can be done easier?
I also would like to know if it makes any difference performance wise by just using item.ForumPosts() or starting a new query, I think the forumposts are already in the ForumThreads collection and don't require a new database call right?
I hope someone can point me in the right direction!
Thank you for your time and merry christmas.
Kind regards,
Mark
This goes a bit late, but. You can instead of using the Query tool use something like this:
ForumPostsCollection posts = new ForumPostsCollection().Where(ForumPosts.Columns.ThreadId,1).Load();
You can use as many parameters as you want just repeat the where clause like:
ForumPostsCollection posts = new ForumPostsCollection().Where(ForumPosts.Columns.ThreadId,1).Where(ForumPosts.Active,true).Load();
You can even use a comparison in the one of the Where methos overloads.
A for paged results, I am sure you can do it, but I dont have subsonic here with me atm, and i cannt find anything in the docos for version 2.2, there is something for v3 though.
About your second question, Subsonic uses Lazy Loading of collections, meaning that when you execute the method ForumPosts, it issues another database call to fecth that collection. The same is not true for Parent entities, the rule here is if its a method eg: ForumPosts() - A new database call is done, it it is a property eg: post.Thread it will be loaded.
Related
How can I replace a Views 3 query with a custom SQL query in code?
From what I understand, you can use hook_views_query_alter to modify the query. I would assume you could also use it to replace the query. Here are a couple hook_views_query_alter examples, to get you started:
Using Hook Views Query Alter
Alter a View query to add a WHERE clause with OR group operator.
This might no longer be pertinent to you, but there's what seems to be a very useful discussion on Drupal.org at Implementing custom SQL query for Views / Filters that looks like it's answering my similar question.
In particular, the initial poster has suggested attaching to hook views_views_pre_execute, which someone else mentioned can be put into a custom module like:
function mymodulename_views_pre_execute(&$view) {
if($view->name=="groups_list2") {
// ...
$view->build_info['query'] = "SELECT node.nid AS nid ".
"FROM node WHERE node.type='%s'"; // wrapped for legibility
}
}
And another poster mentioned mySQL Views and Table Wizard (direct link), though they did mention it's worth bearing in mind this article about mySQL Views performance
It's definitely worth reading the whole thread on Drupal.org, though, as I found it really useful; I hope someone else does too.
Update: Indeed, this is precisely what we're now doing — overriding views_views_pre_execute in a custom module to inject new SQL before it gets to the database. I had opened a similar (but more specific) question on Drupal.SE at Slow query with large dataset in Drupal views — better to process in SQL or PHP?, which you might find useful.
If you want to execute custom SQL (that Views cannot generate), for example computed fields, or complicated SQL joins, then what you are after is a custom module.
See drupal for a guide to get you started
Good afternoon ladies and gents --
I've been tasked with finding and fixing a bug in an unfamiliar legacy application that had some recent changes made to it, but I don't have an easy way (that I know of) to test my theory. I'm hoping your collective knowledge will verify the test for me.
This application lazy loads lookup lists (tongue-twister?) into DataTables from a database and stores them as an object in HttpContext.Current.Application (an HttpApplicationState).
Before the changes were made, one of the lookup tables was bound to a DropDownList in the following manner (contrived):
Me._lookupList = TheSession.LookupCache.SomeLookupListName.DefaultView
...
ddl.DataSource = Me._lookupList
where 'SomeLookupListName' is a read-only property that returns a DataTable from HttpContext.Current.Application. The changes added some code that filters the private Me._lookupList (DataView) before being bound to the DropDownList:
Me._lookupList.RowFilter = "SomeTableIDColumn <> " & ...
What's happening, if you haven't guessed it already, is that that DataView is now filtered for every user of the application. I looked around the code and found that most other lookup lists are copied to local members in this fashion:
Me._lookupList = New DataView(TheSession.LookupCache.SomeLookupListName)
Since I don't know how to attack my local debug session pretending to be multiple users, will changing the code to use the latter method actually be any different than the former? Does filtering the result of DataTable.DefaultView actually apply the filter to the underlying DataTable differently than if wrapping the table with a New DataView(...)?
Would it make sense to simply clear the row filter after the DropDownList is bound (seems like a bad solution)? I'd like to stick to the ugly conventions this application uses so that I don't surprise another developer down the road who gets a similar task, otherwise I'd just bypass the application state and grab the items right out of the data repository.
I appreciate your feedback.
Does filtering the result of
DataTable.DefaultView actually apply
the filter to the underlying DataTable
differently than if wrapping the table
with a New DataView(...)?
Yes. It creates a new view which the filter is applied to. The filter is not applied to the table directly. Following the pattern to use the new view will work.
BTW, easy to test multiple sessions against your debugger. Just open up two different browsers (IE and FF) and point to the same app. User login might be the same, but the sessions will be unique.
I have built my first MVC solution and used the repository pattern for retrieving/inserting/updating my database.
I am now in the process of refactoring and I've noticed that a lot of (in fact all) the methods within my repository are hitting the database everytime. This seems overkill and what I'd ideally like is to do is 'cache' the main data object e.g. 'GetAllAdverts' from the database and to then query against this cached object for things like 'FindAdvert(id), AddAdvert(), DeleteAdvert() etc..'
I'd also need to consider updating/deleting/adding records to this cache object and the database.
What is the best apporoach for something like this?
My knowledge of this type of things is minimal and really looking for advice/guidance/tutorial to point me in the right direction.
Thanks in advance.
This just hit my radar, and I assume you have already solved the issue by now. But if not, I would look into Pre-Compiled LINQ Queries. Something like this:
private static Func<SomeDataContext, int, PersonDto> _getPersonByIdQuery =
CompiledQuery.Compile<SomeDataContext, int, PersonDto>(
(dataContext, personId) =>
dataContext.PersonDtos.where(c => c.PersonId == personId).FirstOrDefault()
);
Put something like that inside of your datacontext, then add an internal method in there to call it call it. Your retriever/saver will then call the internal method. Does that make sense? I can post more code if necessary..
Best of luck,
Justin
I'm just trying the ASP.Net Entity framework its the first time I've tried to use an ORM framework so bear with me If I'm barking up the wrong tree.
To simplify the problem I've got the following 2 tables
Calendar
CalendarID
UserID
Date
EventName
Users
UserId
Username
I've added them both to my Entity Framework model and its established the link between the tables. I'm able to then display a list of Calendars from my MVC view, by using something like
<%= calendarEntry.DateAdded%>
However if I then try to use
><%= calendarEntry.Users.Username%> : <%= calendarEntry.DataAdded%>
It falls over on the call to calendarEntry.Users as it says it is null. Why is the entity framework not pulling through the use details? Do I need to change something in my model designer?
If it helps the code in the MVC controller that sends the data to the view is like this
var Entities = new UnityGamersEntities();
return View(Entities.Calendar);
Really hope that makes sense.
for anyone interested I solved this by using the following code
UnityGamersEntities db2 = new UnityGamersEntities();
ObjectQuery<GameCalendar> gc = db2.GameCalendar.Include("GameTitles");
There seems to be a real lack of tutorials for the entity framework, unless you only ever want to work with single tables I found it really hard to find the information I need.
hopefully this will change in coming months.
Gav,
There is another way you can get Linq to Entities to populate the Users Table.
Every Foreign Key and Collection has a "Load" Method on it which will go off to the database and, in your case, fetch the list of users linked to the current calendar and populate the collection. It's kind of like lazy loading.
If you were to add this line it should work:
<!-- Load up Users unless it's already Loaded -->
<% if(!calendarEntry.Users.IsLoaded) calendarEntry.Users.Load(); %>
<!-- Your Line -->
<%= calendarEntry.Users.Username%> : <%= calendarEntry.DataAdded %>
Hope it helps.
PS - I hear you on the lack of documenation
Crafty
You need to tell the entity framework to load the Users for the Calendar.
You can do this VIA the LINQ query, simply:
Calendar cal = (from c in Calendar
where c.CalendarID.Equals(input)
select new
{
c,
c.Users
}).FirstOrDefault().c;
Which says, load the calendar and all its users.
EDIT: There are probably other ways to load the users, this is just the LINQ way.
I have a problem with Gridview sorting that is similar to others but I'm binding to a collection object as opposed to a data table.
The existing business rules and data access layers of an application follow the pattern of having an object and, if you need a collection of objects of that type, to have another class inheriting CollectionBase and implementing IBindingList.
For desktop applications, it was easy to databind a gridview to one of these objects and there weren't any problems with turning on column sorting. Everything was 'in state' in the desktop app's presentation layer.
Now that code is being moved to a new web application (ASP.NET 2.0, VB codebehind pages).
I've played around with what I had to do to only have certain columns of the collection show up in the gridview and the gridview looked pretty good. When I turned on 'allow sorting', that's when the problems showed up.
I'm getting the error about not having a .Sorting method, etc. In researching this, I found all sorts of solutions that were easily implemented with dataviews if my source was a data table. But it's not - it's a collection. I tried to "cheap shot" a datasource by converting the collection to an XML memory stream and them trying to .ReadXML back into a dataset but that didn't work [Root element is missing error was as far as I got in the dataset.ReadXml(ioTemp) where ioTemp was the System.IO.MemoryStream used in the xml serializer].
Because of the old desktop apps, I've never had to worry about sorting a collection since the gridview handled it once it was loaded. In fact, it's a 'standard' that the collection's .SortProperty, .SortDirection and .ApplySort all through NotSupportedExceptions (I inherited this code from programmers long gone).
Is there an easy way to convert the collection to a data table or a way to sort the collection without having to go back to the database each time? Object Data Sources won't work becuase of the intricate rules in how the objects are built - the wizards in VS2005 just can't handle what we need to do (grabbing data from several tables conditionally to make an object).
Thanks in advance.
Have you considered client side sorting instead?
I have used the jquery tablesorter plugin in the past with ASP Gridviews.
http://tablesorter.com/
I had a similar issue and i needed to implement IComparable on the objects. Basically to sort a collection of objects you need a way to distinguish their order. The IComparable interface has one method called Compare which allows the .Net framework to work out the order of the objects when you sort them. You need to implement this method yourself to get the sort method to work.
Google results
You don't mention the error message so i cant be sure if this is the case, can you post the error?
EDIT :
In regards to your comment; you can implement multi column sorting, it just requires more work. You can specify the fields to sort the collection by and then use this information within the CompareTo Method.
Have a look at this
Given that you apparently are populating the grid with a collection of your own objects, this sounds like a perfect job for Linq for Objects. With just a little elbow grease you can achieve what is effectively an SQL Select statement against your collection. Very cool stuff.
http://www.hookedonlinq.com/LINQtoObjects5MinuteOverview.ashx
Also, do you really just want to sort the data in the grid? If so, then'd definitely pursue using Linq against your objects. However, rarely does sorting the contents of the grid really answer the problem ("sorting the grid" usually translates into changing the access path of the data used to fill the grid.) Browser apps aren't like Windows apps and don't have a full-time connection to the underlying data source to make things happen quite as magically as the DataGridView in Windows makes things seem.
You can put link buttons with an On_Click event as the header's of each column.
When the event is triggered, figure out which header was clicked on (one method per header or a commandArgument value). Once that is know, do a .orderBy or .OrderByDescending by on the collection of objects, and put the result back in as datasource of the gridview and databind on that.
In the year since I originally asked this question, I managed to get a new 'standard' implemented so that collections of business objects were now generic lists.
So now a "Collection class" that is little more than a "Inherits List(Of MyBusinessObject)" with a Sort Method that looks like this (performance wasn't an issue):
Public Overloads Sub Sort(ByVal strPropertyName As String, ByVal strDirection As String)
Dim arSortedList As New ArrayList
For Each item As MyBusinessObject In Me
arSortedList.Add(item)
Next
arSortedList.Sort(New CaseInsensitiveComparer(Of MyBusinessObject)(strPropertyName, strDirection))
For intI As Integer = 0 To arSortedList.Count - 1
Item(intI) = arSortedList(intI)
Next
End Sub
This seemed to work perfectly with the methodology used by the GridView for firing events.