NHibernate Hanging on Lazy Loaded Query - nhibernate

First of all, I'm using Fluent NHibernate with LinqToNHibernate.
I've got a query to do a search on a table based on what data the user entered. So, for example, I'm doing something like this:
'build the initial query that we will filter--this is lazy loaded
Dim results As IEnumerable(Of Customers) = Me.GetCustomers()
'filter by owner name
If String.IsNullOrEmpty(OwnerName) = False Then
results = results.Where(Function(s) s.Name.Contains(OwnerName))
End If
'execute query
results = results.ToList()
So essentially I'm building a where statement on the sql statement if the user wants to search by name. I'm using all lazy configurations in my mappings, so the query shouldn't be retrieving the items until the "ToList()" is called. The problem is that NHibernate hangs on this statement. I thought at first it was because there were so many records in the db(about 500,000).
But I changed the line where I am filtering the results to this:
results = SessionFactoryProvider.SessionFactory.CurrentSession.Linq(Of Customer).Where(Function(c) c.Name.Contains(OwnerName))
And it works very quickly. But I can't seem to figure out why. Any ideas?

In the first case you are retrieving all the records and using Linq-to-objects to filter that list.
In the second case, you are sending the query to the database (NHibernate.Linq converts your expression into a SQL WHERE clause).
Now, I don't know what is the return type of GetCustomers, but since you're storing it into an IEnumerable(Of Customer), .NET has no way of knowing about an underlying provider. If GetCustomers' code is something like:
Return CurrentSession.Linq(Of Customer)
...Then the problem is with that conversion. Just change the first line to:
Dim results As IQueryable(Of Customers) = Me.GetCustomers()

Related

Simple.Data Eager Load SimpleQuery object

It appears that Simple.Data will lazy load by default.
I simply want Simple.Data to query the database and put the results in an object. For example, as soon as this piece of code is executed the results from the database should be stored in employeeData and the database should not be called again:
var employeeData = db.Employee.FindAllByEmployeeId(employeeId) .Where(db.Employee.EmployeeId == 1);
How do I do this? The Simple.Data documentation only describes how to eager load joins. I do not require any joins, simply to get results from a table when I choose to. If I include this WithEmployee() it will do a left join on the Employee table and output the same data twice...
Figured it out... turns out I can just create a list from the output which will save the data
eg.
.ToList<Employee>()

Paging dynamic query results

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);
}
}

Selecting specific joined record from findAll() with a hasMany() include

(I tried posting this to the CFWheels Google Group (twice), but for some reason my message never appears. Is that list moderated?)
Here's my problem: I'm working on a social networking app in CF on Wheels, not too dissimilar from the one we're all familiar with in Chris Peters's awesome tutorials. In mine, though, I'm required to display the most recent status message in the user directory. I've got a User model with hasMany("statuses") and a Status model with belongsTo("user"). So here's the code I started with:
users = model("user").findAll(include="userprofile, statuses");
This of course returns one record for every status message in the statuses table. Massive overkill. So next I try:
users = model("user").findAll(include="userprofile, statuses", group="users.id");
Getting closer, but now we're getting the first status record for each user (the lowest status.id), when I want to select for the most recent status. I think in straight SQL I would use a subquery to reorder the statuses first, but that's not available to me in the Wheels ORM. So is there another clean way to achieve this, or will I have to drag a huge query result or object the statuses into my CFML and then filter them out while I loop?
You can grab the most recent status using a calculated property:
// models/User.cfc
function init() {
property(
name="mostRecentStatusMessage",
sql="SELECT message FROM statuses WHERE userid = users.id ORDER BY createdat DESC LIMIT 1,1"
);
}
Of course, the syntax of the SELECT statement will depend on your RDBMS, but that should get you started.
The downside is that you'll need to create a calculated property for each column that you need available in your query.
The other option is to create a method in your model and write custom SQL in <cfquery> tags. That way is perfectly valid as well.
I don't know your exact DB schema, but shouldn't your findAll() look more like something such as this:
statuses = model("status").findAll(include="userprofile(user)", where="userid = users.id");
That should get all statuses from a specific user...or is it that you need it for all users? I'm finding your question a little tricky to work out. What is it you're exactly trying to get returned?

SubmitChanges with LINQ to SQL and User Defined Functions

On the SQL server I create a UDF. Let's name it fnCompanyDetails. It selects some information about a company from several joint tables.
I then drag-and-drop this function in the new .dbml of my VB project. I want to use it with LINQ. Smth like this:
Dim company = (From c In d.fnCompanyDetails(sap)
Select New With {
.Sap = c.txtSAP,
.CompanyName1 = c.txtCompanyName1, _
.CompanyName2 = c.txtCompanyName2, _
})
The result of this query I display to the user in a form. If some field is changed I want to send the changes to my database, but is this possible if I'm quering like this, from a UDF?
Thank y
No, it is unfortunately not possible to do in a simple way. Linq-to-sql supports reading to custom types, but only support updates through the entity types that exactly corresponds to a table.
Normally the best way is to always read pure entity objects if they are read with the intention to update them.
Another solution is to create entity objects out of the data returned from the udf and then attach those entities to the context. If you attach the entities in their original state first and then make changes after attaching, you should get away without any change tracking problems.

Table not getting updated while using LinQ

I am trying to update a table using LinQ. Though records are getting inserted, for some reason they are not getting updated.
what can be possible problem
Dim db as new empDataContext
Dim emptable as new employee
if update then
emptable=GetEmp(txtempID.Text)
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
else
emptable.Name="Test"
emptable.Age=11
emptable.City="NYC"
emtable.deptID=10
db.employee.InsertOnSubmit(emptable)
end if
db.SubmitChanges()
Judging just from what I can see here, I'm guessing your GetEmp method is using a different data context to retreive the data than the one you're using to save it back to the DB.
When using LINQ to SQL, the context is what tracks the changes to the tables. If you're not careful and mix Contexts by accident, you can get strange behaviors like this.
You can test by chaging:
emptable=GetEmp(txtempID.Text)
to
// Returns the first matching employee with the id
emptable = (from e in db.Employees
where e.id == txtempid.Text).FirstOrDefault()
If you find that the context is the issue, just modify your GetEmp method to accept the context as a parameter rather than creating a new one itself.
What does GetEmp do? In particular, as presented it appears that it does not have a reference to the empDataContext named db. DataContexts are examples of identity maps and as such they track items that have been loaded from a persistence mechanism. If you are using a different DataContext in GetEmp then the DataContext db does not know about the instance of employee with SomeID equal to the value represented by txtempID.Text.
So either pass a reference to db into GetEmp or change your code to the following:
emptable = db.Single(Function(e as employee) e.SomeID=Int32.Parse(txtempID.Text))
then your update should work.
If I had to guess, I would say that the GetEmp() call is not using the same database context object. Therefore, Linq-To-SQL doesn't think any changes are occuring in the "db" database context.
Randy