How to create a fully dynamic linq query? - c#

I need to build about 30 different administration pages to add/edit/delete records from 30 different tables. I could obviously spend the time creating 30 unique pages, to query each table, but I'm curious if there's a way to simply create a single, dynamic page that queries a single, dynamic linq query. This linq query then returns all fields & records from a specified table.
I've seen examples of dynamic linq similar to this one (http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx), but that still requires hardcoding the table name into the query. I'd like to do a select all similar to this, where I pass in the name of the table (i.e. "Products", "Orders", etc), and then somehow query that table:
private List<tableName> MyDynamicQuery(string tableName)
{
IEnumerable<tableName> dynamicList;
using (MyEntities db = _conn.GetContext())
{
dynamicList = (from q in db.<tableName>
select q).ToList();
}
return dynamicList;
}
Is something like this even possible to do?
Thanks

Instead of using table names, why don't you pass in a selector? It would look something like this:
private List<T> GetData<T>(Func<MyEntities, IEnumerable<T>> selector)
{
using (MyEntities db = _conn.GetContext())
{
return selector(db).ToList();
}
}
You'd use it like so:
var orders = GetData(db => db.Orders);

You could use entity framework and do this:
dynamiclist = this.datacontext.Set<T>().ToList(); // where T is the Type, represents the table in EF

Related

Linq to SQL use view instead of query

I have an entity in linq to SQL that i query. The query result, of the kind IQueryable is passed through repository and is manipulated in various way.
I noticed that the first query i do, to fetch the first IQueryable is not efficient due to poor ORM translation (and there is nothing more i can do from ORM side), and i would like to use a view instead.
But i don't know how to plug in a view so that it will produce a IQueryable<MyTable> instead of IQueryable<MyView>.
Here an example :
public class MyRepository
{
MyDataContext _dataContext = new MyDataContext();
public IQueryable<MyTable> ComplexRead (..parameters..)
{
return _dataContext.MyTables.Where (..something too complex..); //i would change this query with a view
}
public IQueryable<MyTable> Paging (IQueryable<MyTable> source, int page, int pageSize )
{
return source.Skip(page*pageSize).Take(pageSize);
}
}
public class Program
{
static void Main(string[] args)
{
var repository = new MyRepository();
var query = repository.ComplexRead (..params..);
var result = repository.Paging (query ,0,10);
}
}
As you can see i need to pass IQueryable arround (in a complex project so not easily replaceable), then consider that the Linq table of MyTable will load data with some prefetch (so all the dependant entity are fetched at once).
Because ComplexRead is not optimizable enought with linq (take this fact as granted) i need to replace it with a view. The veiw return the same structure that the un-optimized ORM generated query will (tested with SQL Profiler) so in theory can be replace the table (with all prefetch); but i don't know how to tell to ORM to use that view to fetch MyTable data.

Convert Dictionary to anonymous object in c#?

I have a web API I'm building in C#. This web API is used as a front end to query a SQL database. I am using SqlKata as the engine to perform the querying. When generating a WHERE clause, the SqlKata documentation states the following:
Multiple fields
If you want to filter your query against multiple fields, pass an object that represents col/values.
var query = new Query("Posts").Where(new {
Year = 2017 ,
CategoryId = 198 ,
IsPublished = true,
});
I want to be able to avoid hardcoding the WHERE clause, but rather base it on passed in querystrings. My idea was to add each querystring name and value to a Dictionary then somehow use the values of that Dictionary within the SqlKata .Where() clause. I thought maybe I could convert the Dictionary to the required anonymous object, but I can't get it to work. Any ideas folks on how to do this? So my url might be:
https://webapi.com.au/api?store=120&name=james
Dictionary:
store=120
name=james
Query:
var query = new query("Posts").Where(anonObject)
( anonObject would be {store=120,name=james} )
You don't need an anonymous object. Looking at the SqlKata docs, you can just build up the query by looping over the dictionary, something like this:
//Assuming the dictionary is something like Dictionary<string, object>
var query = new Query("Posts");
foreach(var element in dictionary)
{
query = query.Where(element.Key, element.Value);
}
var result = query.Get();
Note: Never even heard of SqlKata before so this is just from looking at the docs.

Using variables to build a LinQ query?

I don't think is possible but wanted to ask to make sure. I am currently debugging some software someone else wrote and its a bit unfinished.
One part of the software is a search function which searches by different fields in the database and the person who wrote the software wrote a great big case statement with 21 cases in it 1 for each field the user may want to search by.
Is it possible to reduce this down using a case statement within the Linq or a variable I can set with a case statement before the Linq statement?
Example of 1 of the Linq queries: (Only the Where is changing in each query)
var list = (from data in dc.MemberDetails
where data.JoinDate.ToString() == searchField
select new
{
data.MemberID,
data.FirstName,
data.Surname,
data.Street,
data.City,
data.County,
data.Postcode,
data.MembershipCategory,
data.Paid,
data.ToPay
}
).ToList();
Update / Edit:
This is what comes before the case statement:
string searchField = txt1stSearchTerm.Text;
string searchColumn = cmbFirstColumn.Text;
switch (cmbFirstColumn.SelectedIndex + 1)
{
The cases are then done by the index of the combo box which holds the list of field names.
Given that where takes a predicate, you can pass any method or function which takes MemberDetail as a parameter and returns a boolean, then migrate the switch statement inside.
private bool IsMatch(MemberDetail detail)
{
// The comparison goes here.
}
var list = (from data in dc.MemberDetails
where data => this.IsMatch(data)
select new
{
data.MemberID,
data.FirstName,
data.Surname,
data.Street,
data.City,
data.County,
data.Postcode,
data.MembershipCategory,
data.Paid,
data.ToPay
}
).ToList();
Note that:
You may look for a more object-oriented way to do the comparison, rather than using a huge switch block.
An anonymous type with ten properties that you use in your select is kinda weird. Can't you return an instance of MemberDetail? Or an instance of its base class?
How are the different where statements handled, are they mutually excluside or do they all limit the query somehow?
Here is how you can have one or more filters for a same query and materialized after all filters have been applied.
var query = (from data in dc.MemberDetails
select ....);
if (!String.IsNullOrEmpty(searchField))
query = query.Where(pr => pr.JoinDate.ToString() == searchField);
if (!String.IsNullOrEmpty(otherField))
query = query.Where(....);
return query.ToList();

Using Dapper to map more than 5 types

I am currently building a SELECT query that joins 12 tables together. I've been using Dapper for all my other queries and it works great. Problem is, the generic methods only have to five generic parameters.
I've previously modified the code to support up to 6 for another query, but now I really don't think I should be hacking 6 more levels of generics.
Is there a way to pass dapper an array of types, and it returns the results as an array of objects, which I can cast manually if I have to?
I also might be approaching the problem the wrong way! Any help will be appreciated!
In a project I worked on I saw something like this to get more than 7 types mapped. We used Dapper 1.38:
connection.Query<TypeOfYourResult>
(
queryString,
new[]
{
typeof(TypeOfArgument1),
typeof(TypeOfArgument2),
...,
typeof(TypeOfArgumentN)
},
objects =>
{
TypeOfArgument1 arg1 = objects[0] as TypeOfArgument1;
TypeOfArgument2 arg2 = objects[1] as TypeOfArgument2;
...
TypeOfArgumentN argN = objects[N] as TypeOfArgumentN;
// do your processing here, e.g. arg1.SomeField = arg2, etc.
// also initialize your result
var result = new TypeOfYourResult(...)
return result;
},
parameters,
splitOn: "arg1_ID,arg2_ID, ... ,argN_ID"
);
The queryString is self-explanatory. The splitOn parameter says how Dapper should split the columns from the SELECT statement so that everything can be mapped properly to the objects,
you can read about it here.
You could use a dynamic query and map it afterwards. Something like this
var result = conn.Query<dynamic>(query).Select(x => new Tuple<Type1, Type2, Type3, Type4, Type5>(
// type initialization here
new Type1(x.Property1,x.Property2),
new Type2(x.Property3,x.Property4),
new Type3(x.Property5,x.Property6) etc....));
Edit: With a rather huge result set, another option might be to use multiple querys and then use a Grid Reader. That might work for you.
There's the example taken from the dapper age:
var sql =
#"
select * from Customers where CustomerId = #id
select * from Orders where CustomerId = #id
select * from Returns where CustomerId = #id";
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
...
}
This has been answered long time ago, but I would like to add my two cents here. Instead of manually modify Dapper's source code, why don't you just create a poco class with those fields and use your query like a table?
The mapping would work fine, I know it is a pain also to do that class definition, but seems easier than dealing with later Dapper's updates.

First SQL to Linq Conversion

I am new to LINQ, can somebody guide me that how can I convert the following SQL Query in Linq.
Select tblIns.InsID, tblProg.ProgName
from tblIns, tblProg
Where tblIns.InsID = tblProg.InsID
I am working on MVC2 Project, I have dataContext and Reposetories , please find below the code where I need this query:
public IQueryable<tblInstitute> InsRepeater()
{
return from Inst in _db.tblInstitutes
from Progs in _db.tblPrograms
Where Inst.InstituteID = Progs.InstituteID
Select Inst.InstituteID, Progs.ProgramName
}
The first thing you need is a data context which emulates your database. Here is an example of how to do this with linq to sql. You can also do it with entity framework (EF) or any other provider.
Once you have the tables created, the query then translates pretty straight forward:
var results = from insEntity in tablIns
from progEntity in tablProg
where insEntity.InsID equals progEntity.InsID
select new { insEntity.InsID, progEntity.ProgName };
With the question you have asked, this is as much as I think will be useful. In the future it's best to write questions explaining what you are trying to do, what you have tried, and then where you are stuck. The question should be specific enough to get you just over the next hump.
Per your edit: The query you have needs to have lowercase where and select and it needs to end the statement with a semi-colon (assuming it is c#). Then you select statement needs to select a new object. The results would look something like this:
public IQueryable<tblInstitute> InsRepeater()
{
return from Inst in _db.tblInstitutes
from Progs in _db.tblPrograms
where Inst.InstituteID equals Progs.InstituteID
select Inst; // for the current method header
//select new { Inst.InstituteID, Progs.ProgramName }; // to use this one you'll have to create a new type with the properties you want to return
}
First you need to
1. Create entity classes.
2. The data context.
3. Define relationships
4. Query
Reference
from I in tblIns
from P in tblProg
Where I.InsID = P.InsID
Select I.InsID, P.ProgName
Assuming you have your foreign keys set up properly in the database you can just do this, there is no need to to the joins yourself:
from x in db.tblProgs
select x.tblIns.id, x.Progname

Categories