Generate LINQ query from multiple controls - sql

I have recently written an application(vb.net) that stores and allows searching for old council plans.
Now while the application works well, the other day I was having a look at the routine that I use to generate the SQL string to pass the database and frankly, it was bad.
I was just posting a question here to see if anyone else has a better way of doing this.
What I have is a form with a bunch of controls ranging from text boxes to radio buttons, each of these controls are like database filters and when the user hits search button, a SQL string(I would really like it to be a LINQ query because I have changed to LINQ to SQL) gets generated from the completed controls and run.
The problem that I am having is matching each one of these controls to a field in the database and generating a LINQ query efficiently without doing a bunch of "if ...then...else." statements. In the past I have just used the tag property on the control to link to control to a field name in the database.
I'm sorry if this is a bit confusing, its a bit hard to describe. Just throwing it out there to see if anyone has any ideas.
Thanks
Nathan

When programming complex ad-hoc query type things, attributes can be your best friend. Take a more declarative approach and decorate your classes, interfaces, and/or properties with some custom attributes, then write some generic "glue" code that binds your UI to your model. This will allow your model and presentation to be flexible, without having to change 1000s of lines of controller logic. In fact, this is precisely how Microsoft build the Visual Studio "Properties" page. You may even be able use Microsoft's "EnvDTE.dll" in your product depending on the requirements.

You could maybe wrap each control in a usercontrol that can take in IQueryable and tack on to the query if it is warranted.
So your page code might go something like
var qry = from t in _db.TableName
select t;
then pass qry to a method on each user control
IQueryable<t> addToQueryIfNeeded(IQueryable<t> qry)
{
if(should be added)
return from t in qry
where this == that
select t;
else
return qry
}
then after you go through each control your query would be complete and then you can .ToList() it. A cool thing about LINQ is nothing happens until you .ToList() or .First() it.

I don't know about the performance here, but if you set up the LINQ to SQL data context class you should be able to query a database table with a .Select(...) or .Where(...). You should be able to build lambda expressions for either of these dynamically. You might look into dynamic generation of lambda expressions for this purposes. I have done everything up to the point of the dynamic lambda generation, but it is possible.

I'm not 100% sure how to achieve this but I know where a good place to start would be, in the ASP.NET MVC source. In recent versions it is capable of taking the form response and pass it into a helper method which does the writing to a LINQ data source.
I believe MVC is C# so if you're looking for a VB translation you could try using .NET Reflector and converting it back to VB.

I think you are searching how to create a "Dynamic" Linq Query, Here is an example about how to do it with a library of extension methods. Those methods take string arguments instead of type-safe language operators.

I don't mind sfusco's method by using attributes. The only thing that i'm not sure of is where to attach the attributes to because If I attach then to the controls declaration which is in the designer code it will get regenerated when the form changes.
Or am I completely misunderstanding sfusco's methods?

I think perhaps the right way to do this would be an extender provider: MSDN documentation
Then, you can use the editor to provide the field names to hook up with, and your extender provider can be passed an IQueryable<T>, add the criteria, and return an IQueryable<T>.

Related

Access Queries in Visual Studio with Devexpress

I have recently decided to re-develop an access VBA application in VB .net with DevExpress.
I have managed to figure out databinding with the raw tables. However, I am struggling with the queries.
I have tried the query builder, but I dont have the option to save them and bind object to it. I assume it works this way? As it did in access? Or is the query builder there simply to help you format the SQL text?
I am trying to bind a DataGrid to a simply join query without any luck.
Can you someone point me in the right direction?
Thanks.
There are two main approaches that I can think of. One is to use datatables, and the other is to use domain objects.
Datatables are quick to write, can easily handle most of the heavy lifting for you (including CRUD operations) and are pretty scalable, as changes to the underlying object can be handled relatively easily.
DataTable dt = new DataTable();
Domain Objects (aka POCOs) take a lot of up-front work but typically in the log run make for a more bulletproof and robust solution. Plus, there are frameworks and even Micro ORMs that will do much of the heavy lifting for you, if you choose to use them.
List<DomainObject> do = new List<DomainObject>();
These work with tables, views or queries. You mention you have this figured out for a table, so I'm guessing you have already sort-of gotten this far.
So, first step -- figure out which direction you want to go. (pick domain objects)
Second step -- I recommend using a binding source (System.Windows.Forms.BindingSource). Make your data table / collection the DataSource for the binding source.
Third step, make the binding source the data source for your grid. If you are using a Domain Object, you'll see the columns populate automatically.
From there, once the datatable or collection is populated, you can assign it as the data source for the binding source, and .NET and Dev Express will take care of the rest for you.
bindingSource1.DataSource = dt;
or
bindingSource1.DataSource = do;
Now if you're talking CRUD operations -- that's a horse of a different color. You still use these as building blocks, but this is in no way a comprehensive answer for that.
By the way, the code above is C#, so you need minor tweaks to get this to be VB. I don't speak VB, otherwise I would have just done it like that to begin with.

How do I strongly type criteria when using NHibernate's CreateCriteria method?

I'm currently using NHibernate, for the first time, with Fluent NHibernate. I've gotten everything setup nicely, however now I've come to actual doing some data retrieval, it seems to have fallen short.
I was expecting NHibernate, to allow me to do something like:
session.CreateCriteria<TblDocket>()
.Add(Restrictions.Eq(x=> x.DocketNumber, "10101"));
However, this doesn't appear to be the case and I seem to have to write:
session.CreateCriteria<TblDocket>()
.Add(Restrictions.Eq("DocketNumber", "10101"));
That'll be less-than-wonderful when I rename any properties! I've always though hard coded strings in code is bad, especially when the strings relate to property names.
Is there any way I can strongly type these restrictions? I had a look at this blog post, but it seems quite messy, is there a nicer solution?
I decided to use NHibernate.Linq instead. I found a brilliant tutorial here.
You can't using out-of-the-box NHibernate.
There is a project called NHibernate Lambda Extensions which allows you to do this with some limitations.
since NHibernate 3.0 there is also QueryOver available which are a nice typesafe wrapper around the criteria API.
session.QueryOver<TblDocket>()
.Where(x => x.DocketNumber, "10101");
For anyone who comes along this post and doesn't like linq or isn't too familiar with lambda you can still safely use ICrierta's such as
session.CreateCriteria<TblDocket>().Add(Restrictions.Eq("DocketNumber", "10101"));
what you need is helper classes so you can remove the magic strings such as "DocketNumber" so that if you do change your property names or column names these are taken care of for you or will atleast produce a build error so you know before you publish your code.
Anyone wanting to see an example can have a look at NhGen ( http://sourceforge.net/projects/nhgen/ ) and the query examples at https://sourceforge.net/projects/nhgen/forums/forum/1169117/topic/3789112 which show how helpers classes can be used like.
// Find using a simple entity query
IList<IMessage> messageList3 = messageDao.Find( new [] { Restrictions.Le(MessageHelper.Columns.Date, dateLastChecked) } );
Note that this project also created entity wrapper classes which group all your common CRUD methods into one class (xxxDao as show above) so you don't have to keep copying the same code over and over again.

VB.NET switching from ADO.NET to LINQ

I'm VERY new to Linq. I have an application I wrote that is in VB.NET 2.0. Works great, but I'd like to switch this application to Linq. I use ADO.NET to load XML into a datatable. The XML file has about 90,000 records in it. I then use the Datatable.Select to perform searches against that Datatable. The search control is a free form textbox. So if the user types in terms it searches instantly. Any further terms that are typed in continue to restrict the results. So you can type in Bob, or type in Bob Barker. Or type in Bob Barker Price is Right. The more criteria typed in the more narrowed your result. I bind the results to a gridview.
Moving forward what all do I need to do? From a high level, I assume I need to:
1) Go to Project Properties --> Advanced Compiler Settings and change the Target framework to 3.5 from 2.0.
2) Add the reference to System.XML.Linq, Add the Imports statement to the classes.
So I'm not sure what the best approach is going forward after that. I assume I use XDocument.Load, then my search subroutine runs against the XDocument. Do I just do the standard Linq query for this sort of repeated search? Like so:
Dim people =
from phonebook in doc.Root.Elements("phonebook")
where phonebook.Element("userid") = "whatever"
select phonebook
Any tips on how to best implement?
This video shows you how to enable intellisense from XML documents. I use this extensively. Hopefully it helps:
http://www.asp.net/learn/linq-videos/video-216.aspx
Then you can use a list of items already selected to exclude those from the result set.
First, I should mention that var is used with C# and not VB.Net (use dim). Next, you can reuse you linq queries against the xml as often as you want. Unless something modifies the xml in memory, you should be ok.

Concurrency with Linq To Sql Stored Procedures

I come from the asp.net world where we'd use an objectdatasource, hooked up to data access layer, and set it's ConflictDetection property to "CompareAllValues". There is an OldValuesParameterFormatString on the ObjectDataSource that you use to identify old value parameters.
The sql procedure that does an update would then require both new params and old params and that was it... Super simple to implement; the ODS handled the old values for you.
I've moved over to Linq to SQL and WinForms. I've created a WCF service that is our business layer and I have a stored procedure that will update some table. In the data context designer I see that there is an Update Check property on my class columns. I'm not directly updating the table from the class, rather I'm calling a stored procedure to do the update. Is there some way to retain the original values, perhaps from the data context, similar to they way an objectdatasource would?
Are you using stored procedures directly (through a SqlCommand) or through LINQ to SQL? LINQ to SQL supports using stored procs for all its database access. You might want to look at Updating our Database using Stored Procedures, part 7 of Scott Guthrie's blog post series about LINQ to SQL. You can setup the use of sprocs through the DBML designer or in code using a DataContext partial class. The idea is that you send both the new and original values (e.g. Name and OriginalName) to the sproc so it can to its concurrency checking.
If you are using the sproc directly and not through LINQ to SQL, and all you want is to get the object's original values, you can obtain them by using Table<T>.GetOriginalEntityState() like this:
Order modifiedOrder = db.Orders.First(); // using first Order as example
modifiedOrder.Name = "new name"; // modifying the Order
Order originalOrder = db.Orders.GetOriginalEntityState(modifiedOrder);
Not the answer you may be looking for, but since you mentioned using WCF as a business layer along with LINQ2SQL, I felt it is my obligation to point out this article for your reference:
http://www.sidarok.com/web/blog/content/2008/05/26/linq-to-sql-with-wcf-in-a-multi-tiered-action-part-1.html
While the article implements ASP.NET as the main presentation layer, but considering your background, it might actually make the article easier to understand.
I personally handled the same sort of development as you are doing right now (winforms for client, WCF for business logic layer, LINQ2SQL for data access), but being complete beginner to WCF & LINQ2SQL at the time, I basically forced to drop the original values retention. This article comes closest to your needs, though to be honest I've not seen anything that works with using stored procedures.
Ditch the sprocs and create a new DBML file for your tables.
Drag your tables in and bam! LinqToSql will create entity classes for you with methods for updating (creating.. etc).
LinqToSql has a number of approaches for concurrency. One of the overloaded Attach() methods (used for updates) requires 2 params: the original entity and the new entity. LinqToSql will do what the ObjectDataSource used to do and compare the old values with the new and throw concurrency exceptions (it even makes handling concurrency exceptions much easier. +10 ..but that's not your question).
Use this reference, particularly the section towards the bottom called With Complete Entities. It makes a lot of sense and shows how the different concurrency approaches are used and how to handle the exceptions.
hav fun.

What to do with queries which don´t have a representation in a domain model?

This is not specific to any language, it´s just about best practices. I am using JPA/Hibernate (but it could be any other ORM solution) and I would like to know how do you guys deal with this situation:
Let´s suppose that you have a query returning something that is not represented by any of your domain classes.
Do you create a specific class to represent that specific query?
Do you return the query in some other kind of object (array, map...)
Some other solutions?
I would like to know about your experiences and best practices.
P.S.
Actually I am creating specific objetcs for specific queries.
We have a situation that sounds similar to yours.
We use separate objects for reporting data that spans several domain objects. Our convention is that these will be backed by a view in the database, so we have come to call them view objects. We generally use them for summarising complex data into a flat format.
I typically write a function that performs a query using SQL and then puts the results into either a list or dictionary (in Java, I'd use either an ArrayList or a HashMap).
If I found myself doing this a lot, I'd probably create a new file to hold all of these queries. Otherwise I'd just make them functions in whatever file they were needed/used.
Since we're talking Java specifically, I would certainly not create a new class in a separate file. However, for queries needed in only one class, you could create a private static inner class with only the function(s) needed to generate the query(s) needed by that class.
The idea of wrapping that up the functionality in some sort of manager is always nice. It allows for better testing, and management therefore of schema changes.
Also allows for easier reuse in the application. NEVER just put the sql in directly!!!. For Hibernate I have found HQL great for just this. In particular , if you can use Named queries. Also be careful of adding an filter values etc use "string append", use parameters (can we say SQL injection ?). Even if the SQL is dynamic in terms of the join or where criteria, have a function in some sort of manager is always best.
#DrPizza
I will be more specific. We have three tables in a database
USER
PROJECT
TASK
USER to TASK 1:n
PROJECT to TASK 1:n
I have a query that returns a list of all projects but showing also some grouped information (all tasks, open tasks, closed tasks). When returned, the query looks like this
PROJECTID: 1
NAME: New Web Site
ALLTASK: 10
OPENTASK: 7
CLOSEDTASK: 3
I don´t have any domain class that could represent this information and I don´t want to create specific methods in Project class (like getAllTasks, getOpenTasks) because each of these methods would trigger a new query.
So the question is:
I create a new class (somenthing like ProjectTasksQuery) just to hold that information?
I return information within array or map?
Something else?
You might feel better after reading about Data Transfer Objects. Some people plain don't like them, but if it feels like a good fit to you, it probably is.