Dynamically Modifying a LINQ to SQL Select Statement's Columns - c#

I'm trying to build a REST-ful API for my app. Currently I have something like this:
www.example.com/submissions/?format=json
This will return latest ten submissions in JSON. Each object has its details, such as submission name, date created, user, body, etc.
I'd like to do something such as:
www.example.com/submissions/?format=json&filter=name,user
The filter should make the request to return the same result but to only include the details mentioned, i.e. each object will only have a name and user.
This is fairly straightforward in terms of the JSON output. I can load all the columns from the database and create and serialize an object that will only include the columns in the filter. However, I do not want to load all the columns in the database - I want to bother my database with only the columns that I will include in the response.
I want to do something like this:
var result = from record in Submissions
select
{
Name,
Date,
User,
Body
};
Now I have the result object, which is IQueryable, so no call to database made yet.
Then, I should examine the filter querystring and exclude the columns that are not mentioned.
Finally, I can execute the select statement with something like
JavaScript.Serialize(result.ToList());
Is this possible with LINQ to SQL?

An alternative to building your Select expression tree by hand is Dynamic LINQ, which provides a Select method that takes a string:
var filter = "name,user";
var result = Submissions.Select("new(" + filter + ")");
The string is then translated into an expression tree and passed on to your query provider.

Yes. You are going to want to research Modifying Expression Trees. Specifically the MemberInit Expression.

Related

How to generate nHibernate raw sql for Insert/Update without execution?

Is it possible to generate a raw SQL statement for insert/update operations using nHibernate without actually executing them? Assuming of course that everything (mappings, connectionStrings, etc.) is properly configured?
The closest thing I've found is to call:
Session.SessionFactory.GetClassMetadata(typeof(Client))
Which returns an object of type SingleTableEntityPersister containing SQLIdentityInsertString, that looks like this:
INSERT INTO Client (FirstName, LastName) values (?, ?)
But it would still require me to bind all of the properties manually, and on top of that SQLIdentityInsertString is a protected property. Are there any proper ways of doing that?
Okay, the closest thing I've found is to construct your own sql query with a string builder. First you need to extract your class metadata:
var metaData = Session.SessionFactory.GetClassMetadata(typeof(Client)) as SingleTableEntityPersister;
Then you can retrieve other information, such as:
var propertyNames = metaData.PropertyNames;
var tableName = metaData.TableName;
var firstPropertyValue = metaData.GetPropertyValue(client, propertyNames[0], EntityMode.Poco);
Once you have that information you can construct your own query manually. Not exactly the solution I wanted, but it's as close as it gets, I think.
However, one thing to note is that Session.CreateSQLQuery(string) method is currently bugged, and as a result SetParameter method doesn't work with more than 10 named parameters. There already seems to be a bug report created for this on NHbiernate's Jira.

Linq To SQL: Sort Query by Arbitrary Property(Column) Name

I have a larger/more complex problem, but for simplicity sake, let us consider the following:
Let us say that I have table in the SQL DataBase called Product, having two columns, ID (int, primary key) and Name (varchar/string). I also have a simple LINQ DataContext.
I have a query constructed and handed to “my” function. Let us say it is something like: (though it may be a bit more complex)
IQueryable<Product> query = from p in db.Products select p;
Once my method gets this query, passed in as a parameter, it has to change the sort order e.g.
IQueryable<Product> sortedQuery = query.OrderBy(x => x.Name);
I would like to make this more generic i.e. to specify the field to sort on. Normally, I can do a switch statement that takes a string. However I would like to know if there is a way to pass the parameter directly. I intend to extend this to other Database tables, so these switch statements would get tedious.
I was trying something like:
IQueryable<Product> sortedQuery = query.OrderBy(x => (typeof(Product)).GetProperty(“Name”));
But this does not work. I also want to ensure that the LINQ to SQL is maintained i.e. the sort to be done on the SQL Server. Hence if I debug, I should get a SQL query from this LINQ query.
Thank you in advance for your help.
You could use Dynamic Linq for this purpose.
See here Dynamic LINQ (Part 1: Using the LINQ Dynamic Query Library)
Then you can make calls like this:
var query = DBContext.Users.Where( "Age > 3" ).OrderBy( "Name asc" );
Try this out instead:
query.OrderBy(x => x.GetType().GetProperty(“Name”).GetValue(x, null));
You can't just grab the property. You need to grab the value off of that property, hence the call to GetValue.
It is not as easy as it seems. The LINQ to SQL engine parses the expression you pass to the OrderBy method in order to obtain the name of the property you are referencing, then uses this information to compose a plain SQL order by clause.
I guess that maybe it can be done by using reflection, anyway. Maybe you can get something useful from the accepted answer of this SO question.

How to hide some fields using NHIbernate ICriteria?

Here's a scenario that I am working on : Right now we have a SQL statement that reads like this :
SELECT a.ID,a.MsgNumber,CASE WHEN #HasAccess=1 THEN Title ELSE '*********' END AS Title FROM Messages
We want that operators be able to see if a message registered in system but can't see the title if they are not authorized.
I'm changing this part of code so we can use a NHibernate criteria to generate the same result (so we can produce dynamic queries according to filters that user selects).
I know that I can use projections to get some fields or constant values from a criteria but can not figure out how I should combine them to do what I want.
It looks like #HasAccess is a parameter passed in by your code, not a value determined by the database. If so, then the easiest way to do what you want is to modify the criteria in code based on the value that you would pass through in the query, eg:
var projections = Projections.ProjectionList()
.Add(Projections.Id())
.Add(Projections.Property("MsgNumber"))
.Add(hasAccess ? Projections.Property("Title") : Projections.Constant("*********"));
var criteria = session.CreateCriteria<Message>()
.Add(... your restrictions ...)
.SetProjection(projections)
.List<object[]>();
If however #HasAccess is determined by your database somehow, then you could use:
Projections.Conditional(Restrictions.Eq("HasAccess", 1),
Projections.Property("Title"),
Projections.Constant("*********"))
assuming that you can get HasAccess into your criteria somehow

SQL and C# retrieving a single record from database

I have a webpage built with a dropdown that has a list of books. These books are stored on the sql sever. Using the MVC and aspx pages i am trying to figure out how to retrieve information about about a book such that when the user selects a book it passes the price of the book. I am new to sql sever and var statements.
I am able to retrieve the books name from the webpage and send it to my controller
In my model i am trying to get that data here is my thought. I want to get the price and store into a string. But the only way i have seen to pull information is using the var statement.
such that
var price = from p in BooksDB.Price
where p.Book_Name==bookName
select new {p.Book_Price}
but how do i get that value and store it into a string based on the Books_Name that I have retrieved from the dropdown box
by the way my table looks like this
Id_Num Book_Name Book_Price
1 Pro C# 29.99
2 Beg C++ 10.99
First a terminology correction.
var is just a keyword the compiler lets you use to subsitute for the type. During compiletime, the compiler will figure out what the type is based on usage.
var myString = "hihihi";
string myString = "hihihi";
The var statement has nothing to do with accessing a database, although it was added to make using LINQ easier on us lazy developers.
Instead what you are doing is creating a LINQ to SQL query. I've modified it slightly (you don't need to create an anonymous object). After you create the statement, you need to execute it by calling "ToList(), First(), or FirstOrDefault() etc"
LINQ typically employs lazy or deferred evaluation for queries, and isn't executed until you trigger execution.
var price = from p in BooksDB.Price
where p.Book_Name==bookName
select p.Book_Price;
//assuming Book_Price is stored as a string datatype.
string bookPrice = price.FirstOrDefault();
//otherwise
string bookPrice = (price.FirstOrDefault() ?? "").ToString();
if(!String.IsNullOrEmpty(bookPrice))
{
//do something with the string.
}
If I understand correctly something like below should work.
var record = BooksDB.Price.FirstOrDefault(r => r.Book_Name == bookName);
If record is not null at this point then record.Book_Price should contain the data you are looking for (not accounting for ambiguity in the database.)
Instead of select new {p.Book_Price}, use something like select p.Book_Price. You could add .ToString() to the end to force it to come out as a String rather than the data type from the table.
You'll also want to wrap the entire LINQ statement in () and append .FirstOrDefault() to get just one value. The "OrDefault" part protects you from an exception when the result set us empty.

C# NHibernate Issue - Im trying to return Distinct values

C# NHibernate Issue - Im trying to return Distinct values.
This is what I have so far:
IList<TaskFor> objsResult = session.CreateCriteria(typeof(TaskFor)).setProjection(Projections.Distinct).List<TaskFor>();
return objsResult;
I am trying to return a group of values but I need to remove the duplicates.
I cant seem to get set projections to work properly for this instance.
Look forward to hearing any answers.
Thanks,
marc
I'd say this answer from Aidan Boyle could be very helpfull for you.
To perform a distinct query you can set the projection on the criteria to Projections.Distinct. You then include the columns that you wish to return. The result is then turned back into an strongly-typed object by setting the result transformer to AliasToBeanResultTransformer - passing in the type that the result should be transformed into. In this example I am using the same type as the entity itself but you could create another class specifically for this query.
ICriteria criteria = session.CreateCriteria(typeof(Person));
criteria.SetProjection(
Projections.Distinct(Projections.ProjectionList()
.Add(Projections.Alias(Projections.Property("FirstName"), "FirstName"))
.Add(Projections.Alias(Projections.Property("LastName"), "LastName"))));
criteria.SetResultTransformer(
new NHibernate.Transform.AliasToBeanResultTransformer(typeof(Person)));
IList people = criteria.List();
This creates SQL similar to (in SQL Server at least):
SELECT DISTINCT FirstName, LastName from Person
Please be aware that only the properties that you specify in your projection will be populated in the result.
The advantage of this method is that the filtering is performed in the database rather than returning all results to your application and then doing the filtering - which is the behaviour of DistinctRootEntityTransformer.

Categories