LLBLGEN: Linq to LLBGEN don't work - sql

I want to make custom select from the database table using Linq. We use LLBGEN as ORM solution.
I can't do LINQ query to Entities Collection Class unless I call GetMulti(null) method of it.
Is it possible to do LINQ query to LLBGEN without extracting all table first?
BatchCollection batches = new BatchCollection();
BatchEntity batch = batches.AsQueryable()
.Where(i => i.RegisterID == 3)
.FirstOrDefault(); // Exception: Sequence don't contains any elements
batches = new BatchCollection();
batches.GetMulti(null); // I don't want to extract the whole table.
BatchEntity batch = batches.AsQueryable()
.Where(i => i.RegisterID == 3)
.FirstOrDefault(); //Works fine

To query your database using LINQ (which is different from operating on an enumerable collection using the LINQ syntax) you have to use the LinqMetaData provider that comes with LLBLGen in the yourrootnamespace.Linq assembly. Once you add this assembly to your project you can use something like this to create your db query: (from the LLBL documentation)
LinqMetaData metaData = new LinqMetaData();
var q = from c in metaData.Customer
where c.Country=="USA"
select c;
In your example above you are using LINQ syntax to perform a where clause on a collection, but this does not have anything to do with LLBL or executing a query on the database. That is why it will not work with the empty collection, but does work on the filled collection.
Look more into LinqMetaData for the specifics of querying your db using LINQ to LLBLGen.

Related

Entity Framework and LINQ together Batch Update

Afaik Entity Framework 6 doesn't support for batch insert/update/delete.
Is there anyway to make an batch update over an IQueryable object. As an example I have
var query = _db.People.Where(x=>x.Name.Contains(parameter));
an IQueryable (query) object and I want to get the generated sql. Then I hope I can create an update command with this select query like this
Update filteredPerson
Set filteredPerson.Status = 'Updated'
from (here it comes IQueryable Generated SQL :) ) as filteredPerson
over DbContext raw sql execution commands. BTW I don't need EF properties like change tracking and auto detecting. It is just a batch operation.
I know it is pretty risky but I am going to use it for a small piece of code.
Some other logics are appricated. If you know something better, I would like to hear it.
REASON: Why I want to do it this way, because I don't want to spoil the seperation of layers. And there is some validation and filtering comes into the queryable object from other layers. So it is hard to convert it to stored procedure. At the other hand it must be faster than other standard queries.
Again I know there is no support in Entity Framework 6 for batch operations. But other questions are bit outdated. That's another reason why I want to ask this again.
While I was writing the question, I was guessing how I am going to solve it. But I was looking for some more proper way of it. In the end, I know what am I doing and tried to be simple for my colleagues who looking to the same code after me. I know it has some risky usages but I let the exceptions to CLR to handle it. After this excuse :) , I wrote the code like this:
Let's say I have an IQueryable object which is generated with this way:
string parameter = "John";
AdventureWorks2012Entities _db = new AdventureWorks2012Entities();
var query = _db.People.AsQueryable();
//Some parameters added from different layers
query = query.Where(x => x.FirstName.Contains(parameter));
Then I want a batch update over this IQueryable object.
var sqlFrom = query.ToString(); //This is the query which becomes "from table"
var dbq = query.AsDbQuery().GetObjectQuery(); //This does some magic with reflection
var linqParams = dbq.Parameters
.Select(x => new System.Data.SqlClient.SqlParameter(x.Name, x.Value)).ToList();
linqParams.Add(new System.Data.SqlClient.SqlParameter("#ModDate", DateTime.Now));
var sqlBatchUpdate = #"Update filteredPerson Set ModifiedDate = #ModDate From (#FilteredPerson) as filteredPerson"
.Replace("#FilteredPerson", sqlFrom);
var affectedRows = _db.Database.ExecuteSqlCommand(sqlBatchUpdate, linqParams.ToArray());
That's it! Now I don't have to repeat same business logic in stored procedure again. And it is more faster than a foreach and SaveChanges combo.
So I ended up with this for very basic usage. As a fast solution It brings more problems no doubt! But I know I can easily wrap around it for new purposes. So It is up to programmer who wants to use it with more preferences.
Also the code which does the reflection and casting is below and I added a gist for full code:
public static ObjectQuery<T> GetObjectQuery<T>(this DbQuery<T> query)
{
var internalQueryField = query.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.Name.Equals("_internalQuery"))
.FirstOrDefault();
var internalQuery = internalQueryField.GetValue(query);
var objectQueryField = internalQuery.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(f => f.Name.Equals("_objectQuery"))
.FirstOrDefault();
var objectQuery = objectQueryField.GetValue(internalQuery) as ObjectQuery<T>;
return objectQuery;
}
Here is the Gist file. Hope It helps somebody out there.

Linq order by with a field to retrieve dynamically in vb.net

I have a object Ob with several fields f1,..,fn (of different types).
Now a list of object is shown in a GridView and I need to implement the sorting method.
The real problem is:
how can I run
(from ob in Ob_list orderby ob.f1 ascending)
when the sorting field is represented by a string (i.e. "f1")?
Unfortunately I am not able to get it with the reflection (I am not able to do something like ob.GetType().GetField("f1"), this is not mapped into sql code).
I have several fields to possibly sort the rows, which is the best&fastest approach to this?
Thank you very much!
LINQ execution is deferred until you actually enumerate over the results or access the "count", etc. Because of this, you can build up your LINQ statement in stages.
The below code is done in C#, but I'm sure the equivalent is possible in VB.NET.
First setup your basic query:
var query = (from ob in Ob_list);
At this point, nothing has actually gone to the database due to deferred execution.
Next, conditionally add your order by components:
if (sortField == "f1")
{
query = query.OrderBy(o => o.f1);
}
else if (sortField == "f2")
{
query = query.OrderBy(o => o.f2);
}
else
{
//...
}
And finally, collect your results
foreach (var item in query)
{
// Process the item
}
I've found this question: How do I specify the Linq OrderBy argument dynamically?
I'm using Entity Framework, so the first answer did not solved my problem. The second one however, worked great!
Hope it helps!

Call procedure or function as part of Hibernate query

I need to return records filtered and sorted by complex logic.
I am planing to make sorting and filtering at the database side (function or stored procedure).
Is it possible to call procedure or function at the QueryOver or Criteria syntax in order to make filtering of the query?
Something like code shown below, where CallProcedure - calling my procedure/function
var articles = Session.QueryOver<ArticleData>()
.Where(x => x.CompanyId == 1)
.CallProcedure???
.Skip(startIndex)
.Take(number).List();
Thanks for help.
First, you would need to register your function with NHibernate, by creating a custom dialect:
public class MyDialect : MsSqlServer2008Dialect
{
public MyDialect()
{
RegisterFunction("myfunction", new SQLFunctionTemplate(...));
}
}
After that, you can use the function within your query:
var articles = Session.QueryOver<ArticleData>()
.Where(x => x.CompanyId == 1)
.Where(Projections.SqlFunction("myfunction", ...))
.Skip(startIndex)
.Take(number).List();
Something along those lines. Not sure if you'll be able to do both filter and sort with it though. Maybe a database view will be more appropriate for that case.
Some links to get you started:
Can I use SQL functions in NHibernate QueryOver?
NHibernate QueryOver SQLFunction in where clause
Can NHibernate's QueryOver syntax select MAX() of an SqlFunction?

How to delete data in DB efficiently using LinQ to NHibernate (one-shot-delete)

Producing software for customers, mostly using MS SQL but some Oracle, a decision was made to plunge into Nhibernate (and C#).
The task is to delete efficiently e.g. 10 000 rows from 100 000 and still stay sticked to ORM.
I've tried named queries - link already,
IQuery sql = s.GetNamedQuery("native-delete-car").SetString(0, "Kirsten");
sql.ExecuteUpdate();
but the best I have ever found seems to be:
using (ITransaction tx = _session.BeginTransaction())
{
try
{
string cmd = "delete from Customer where Id < GetSomeId()";
var count = _session.CreateSQLQuery(cmd).ExecuteUpdate();
...
Since it may not get into dB to get all complete rows before deleting them.
My questions are:
If there is a better way for this kind of delete.
If there is a possibility to get the Where condition for Delete like this:
Having a select statement (using LinQ to NHibernate) => which will generate appropriate SQL for DB => we get that Where condition and use it for Delete.
If there is a better way for this kind of delete.
Yes, you could use HQL instead of SQL.
If there is a possibility to get the Where condition for Delete [using Expressions]:
No, AFAIK that's not implemented. Since NHibernate is an open source project, I encourage you to find out if anyone has proposed this, and/or discuss it on the mailing list.
Thanks for your quick reply. Now I've probably got the difference.
session.CreateSQLQuery(cmd).ExecuteUpdate();
must have cmd with Delete From DbTable. On the contrary the HQL way
session.CreateQuery(cmd).ExecuteUpdate();
needs cmd with Delete From MappedCollectionOfObjects.
In that case it possibly solves my other question as well.
There now is a better way with NHibernate 5.0:
var biggestId = GetSomeId();
session.Query<Customer>()
.Where(c => c.Id < biggestId)
.Delete();
Documentation:
//
// Summary:
// Delete all entities selected by the specified query. The delete operation is
// performed in the database without reading the entities out of it.
//
// Parameters:
// source:
// The query matching the entities to delete.
//
// Type parameters:
// TSource:
// The type of the elements of source.
//
// Returns:
// The number of deleted entities.
public static int Delete<TSource>(this IQueryable<TSource> source);

Unable to figure out how to do Joins within IQueryable

Here is what I am trying:
IQueryable query = this.MyRepository.GetShippingCollection();
IList<SomeListType> myList = query.Where(x => x.Settings
.Where(y => y.SelectorID.Equals(5))
.Count() > 0)
.OrderBy(x => x.Order)
.ToList();
Produces this error:
could not resolve property: Settings.ID
If I do it this way it works, but causes over 3,000 queries on my SQL Server:
IList<SomeListType> myList = this.MyRepository.GetShippingCollection().ToList();
myList = myList.Where(x => x.Settings
.Where(y => y.SelectorID.Equals(5))
.Count() > 0)
.OrderBy(x => x.Order)
.ToList();
I know the solution resides within using a "Join".
I have been looking at examples for the last couple hours and can only find Join examples within the Mapping file. I am also finding examples for "ICriteria".
I don't want to have to create seporate entries for all my complex queries in the mapping file so the join within that file will not work.
Since I am using Fluent NHibernate, I am not using "ICriteria". I am using "IQueryable". How do you join multiple tables within "IQueryable"?
Any help with this would be greatly appreciated.
Thanks in advance.
If the second query is executing 3,000 queries, it is almost certainly lazy-loading the Settings collection. As you iterate over the list, you access this collection, and each time NHibernate goes back to the database to fetch it. Try setting the fetch mode for the Settings property to eager load in the mapping.
Beyond that, the LINQ provider could be an issue. What version of NHibernate are you using? The 2.x LINQ provider has some real limitations. It has been reimplemented in the 3.0 trunk, but you'll have to download and compile it from the source.
By the way, ICriteria vs IQueryable is not related to Fluent NHibernate. Criteria API and LINQ are two providers through which you can create queries. Fluent NHibernate is an alternative way to perform configuration.