I have a ASP.Net page using ADO to query MS access database and as a learning exercise i would like to incorporate LINQ. I have one simple table called Quotes.
The fields are: QuoteID, QuoteDescription, QuoteAuthor, QuoteDate. I would like to run simple queries like, "Give me all quotes after 1995".
How would i incorporate LINQ into this ASP.Net site (C#)
Basically, my question is does LINQ work for MS Access ??
LINQ to SQL doesn't support Access (that is, there's no Access/Jet provider for LINQ), but you can query a DataSet with LINQ. This means that you fill your DataSet with any possible data from your database that you might need in your results, and then you filter on the client side. After you have a typed DataSet, and you Fill() it with a TableAdapter, you do something like this:
var year = 1995; // you can pass the year into a method so you can filter on any year
var results = from row in dsQuotes
where row.QuoteDate > year
select row;
You'll have to decide whether this is worth it. You'd have to fill your DataSet with all the quotes, then use LINQ to filter on just those quotes that are after 1995. For a small amount of data, sure, why not? But for a very large amount of data, you'll need to make sure it won't be too slow.
If you're using a DataSet, though, you can write custom queries that become new TableAdapter methods. So you can put the correct SQL for your query in a FillByYear() method in your TableAdapter and use that to fill your typed DataTable. That way you're only getting back the data you need.
If you go this route, remember that Access/Jet uses positional parameters, not named parameters. So instead of
SELECT * FROM Quotes WHERE Year(QuoteDate) > #Year
you'd use something like this:
SELECT * FROM Quotes WHERE Year(QuoteDate) > ?
I don't think LINQ to SQL supports Access. However, if your table is sufficiently small to fit into memory, LINQ to DataSet will let you query datatables etc pretty easily - especially strongly typed datasets.
Related
We have a couple of SQL queries as strings:
public class Query
{
public static string CreditTransferId(string expectedValue, string table, int statusId, int messageTypeId, int destination103, int destination202, string StoreStatus202Id)
{
return $"SELECT top 1 Id from {table} where MessageId = '{expectedValue}' and FlowId=3 and StatusId={statusId} and MessageTypeId={messageTypeId} and " +
$" Destination103={destination103} and Destination202={destination202} and StoreStatus103Id is null and StoreStatus202Id {StoreStatus202Id}";
}
}
We have them returned as strings from methods inside the Query class. We want to refactor the code, since we have a method with more than 3 parameters which is pretty hard to use.
How would you go about this? What's the cleanest way to organize SQL queries which need a lot of parameters?
Dynamic SQL is a very bad thing for a start as these are open to SQL injection, you should use parameterise queries and return a string.
"eg: SELECT top 1 Id from [Table] where [MessageId] = #messageId" etc
So you dont need to pass in any values, you would add these to your list of SqlParamater's
The table name is probably pointless as this is related to the sql, so probably just add that into the sql string
This doesn't really need an extra class, just create the sql variable where you call it, so it right there if you need it?
..or use Stored Procedures
..or use Entity Framework
EF is great and you have to decide if that's what you want. There are some cases where it is not suitable. Of u decide to stick with plain text queries how about dividing queries into parts:
FromBuilder
JoinBuilder
GroupBuilder
Condition builder etc
ex.:
return #"
"+new TableIdSelectorBuilder(table).Get() +#"
"+new FromBuilder().Get(table) +#"
"+new TableConditionByIdBuilder(table).Get(I'd)+#"
";
EDIT:
Stored procedures allow to change queries without publishing new app version but is a bit pain in the ass to work on a living organism. At least sometimes.
Hopefully this helps you a bit. I was figuring this out a long time ago too.
Use nameOf instead of hardcoded column names
One advice that I have is: Try to use nameOf() for column names (in case your domain model matches exactly your database structure).
Refactoring becomes a lot easier as well.
Create a query builder
I created a class which allows me to create simple to medium complex queries (Select, Insert, Update, Joins, Deletes, Limit, Offset, ...). For most of the queries that I write I can use this query builder to get what I need and the code will look something like this:
var query = new QueryBuilder()
.Update(nameof(MyTable))
.Set(nameof(MyTable.Name), entity.Name)
.Set(nameof(MyTable.Firstname), entity.Firstname)
.WhereEquals(nameof(MyTable.Id), entity.Id)
.Build();
Unfortunately, I haven't found a good QueryBuilder out there yet. Therefore I created my own.
Use string literals
Microsoft Documentation
Another solution that I recently encountered is by doing the following:
var query = $$"""
SELECT * FROM {{nameof(MyTable)}
WHERE
XX
""";
This at least allows you to indent correctly and the code will remain clean.
Outsource your queries in separate files
I was also thinking about having bigger queries in separate files and include them in the Assembly. When you want to execute the query, you load the query from the file and run it like this.
You might also want to cache that query then, to not always load it from the file.
Final words
Personally, I try to use the QueryBuilder as often as possible. It creates clean code which looks somewhat like LINQ
Backup approach for me is to use the string literals as showed above
Trying to create separate files for queries, I have never tried yet, because there was no use for myself
I would also avoid using Stored Procedures, because they are pain to write and also hard to debug in my opinion
The cleanest option would be to use Entity Framework, but if you want to use Micro-ORMs like Dapper, try one of the solutions above
I am new to Dapper though I am aware about ORMs and DAL and have implemented DAL with NHibernate earlier.
Example Query: -
string sql = "SELECT * FROM MyTable";
public int GetCount()
{
var result = Connection.Query<MyTablePoco>(sql).Count();
return result;
}
Will Dapper convert this query (internally) to SELECT COUNT(*) FROM MyTable looking at .Count() at the end?
Similarly, will it convert to SELECT TOP 1 * FROM MyTable in case of SingleOrDefault()?
I came from NHibernate world where it generates query accordingly. I am not sure about Dapper though. As I am working with MS Access, I do not see a way to check the query generated.
No, dapper will not adjust your query. The immediate way to tell this is simply: does the method return IEnumerable... vs IQueryable...? If it is the first, then it can only use local in-memory mechanisms.
Specifically, by default, Query will actually return a fully populated List<>. LINQ's Count() method recognises that and just accesses the .Count property of the list. So all the data is fetched from the database.
If you want to ask the database for the count, ask the database for the count.
As for mechanisms to view what is actually sent to the database: we use mini-profiler for this. It works great.
Note: when you are querying exactly one row: QueryFirstOrDefault (and the other variants you would expect) exist and have optimizations internally (including hints to ADO.NET, although not all providers can act on those things) to do things as efficiently as possible, but it does not adjust your query. In some cases the provider itself (not dapper) can help, but ultimately: if you only want the first row, ask the database for the first row (TOP or similar).
Is there's way to execute SQL queries directly on dataset or datatable . Query which need to be executed is much complex and it may be difficult to implement with Linq .
Is there any similar way to query directly from dataset or datatable ?
Is there any tools available to convert complex queries to linq ?
There is a DataTable.Select() method, which returns rows that match certain criteria.
The syntax is a little limited, however. Example:
DataTable.Select("Date > #1/1/2014# AND Name = \"John\"");
Should select any rows where the Date column has a date value that's 1/1/2014 or later, and the Name column is "John". Also handy is using String.Format() with it.
DataTable.Select(String.Format("Date > {0} AND Name = {1}", date, name));
This is severely limited compared to fixing it in the actual query, though.
try to use tools like LinqPad or some thing similiar
Download LinqPad
also one other way is to create your complex queries in database as VIEW and then write a simple select from VIEW!
another approach is, using MethodChain
What is the correct way to chain methods in .Net
I use the PreprocessQuery method to extend a query in lightswitch.
Something like this:
query = (from item in query
where (validIDs.Contains(item.tableIDs.myID)) &&
elementCount[item.ID] <= maxEleCount)
select item);
Where validIDs is a HashSet(int) and elementCount is a Dictionary(int, int).
the first where clause is working fine, but the second -> elementCount[item.ID] <= maxEleCount
is not working.
What i want to do is to filter a table by some IDs (validIDs) and check also if in another table the number of entries for every of this IDs does not exceed a limit.
Any ideas?
EDIT
I found a solution. Instead of a Dictionary I also used a HashSet for the second where clause. It seems it is not possible to do the Dictionary lookup inside the LINQ statement for some reason (?)
First, although being a bit pedantic, what you're doing in a PreProcessQuery method is "restricting" records in the query, not "extending" the query.
What you put in a LING query has to be able to be processed by the Entity Framework data provider (in the case of LS, the SQL Server Data Provider).
Sometimes you'll find that while your LINQ query compiles, it fails at runtime. This is because the data provider is unable to express it to the data store (again in this case SQL Server).
You're normally restricted to "primitive" values, so if you hadn't said that using a Dictionary actually worked, I would have said that it wouldn't.
Any time you have a static (as in non-changing) value, I'd suggest that you create a variable outside of your LINQ query, then use the variable in the LINQ query. By doing this, you're simply passing a value, the data provider doesn't have to try to figure out how to pass it to the data store.
Reading your code again, this might not be what you're doing, but hopefully this explanation will still be helpful.
I have several references in DB with same table structure.
I don't want to write several LINQ queries to each db. Is it possible to develop one query with dynamic Table parameter?
My query example:
var query =
from myTranslations in myContext.translations
where myTranslations.code == strLabelCode
select myTranslations;
No, sorry. Simple like that - only via for example reflection, which makes it - ah - hard er than having multiple table objects.
Use datacontext GetTable() method to vary table type as listed here MSDN