How to use Difference function in EntityFrameworkCore? - sql-server

I have this query to be executed :
Select * From Products WHERE Title like '%search text%'
ORDER BY Difference(Title, 'search text') DESC
Now I want to implement the above query using EntityFrameworkCore and linq.
So how can I call difference function to order products by closest match in Title column?

Every IQueryable holds an Expression and a Provider. The Expression holds the query that must be performed. The Provider knows who has to execute the query, usually a database management system. It is the task of the Provider to translate the Expression into the language that the database understands (something SQL-like) and to execute the query. The Provider will fetch the results in an efficient way and return the queried data as an enumerable object.
The IQueryable implements IEnumerable.
When you use LINQ functions like ToList(), FirstOrDefault(), Any(), or use the query in a foreach, then internally IEnumerable.GetEnumerator() is called and Enumerator.MoveNext()
This will order the Provider to translate the Expression into SQL and execute the query. The returned enumerable is used to enumerate over the returned items.
It is the task of the programmer of the class that implements the IQueryable to implement the translation of the Expression into SQL. This is not easy, and I think the people who created entity framework did a great job.
However, some items known in SQL are very difficult to implement. Among those are the notions of SoundEx and Difference. I'm not sure, but I think that one of the reasons that made this difficult is that they are typically something used in SQL, and not in any other kind of IQueryable systems.
In fact, there are a several functions that are not supported by entity framework. See Supported and unsupported LINQ methods (LINQ to entities).
Your DbContext is an abstract representation of your database model. Users of it should not care whether it uses Microsoft SQL, MySQL, or whether it is a data collection that doesn't use anything similar to SQL.
But if you are absolutely certain that it is okay to limit your DbContext to only a certain kind of databases, one that knows the concepts of SoundEx and Difference, consider creating a stored procedure for your query. See How to call a Stored Procedure in Entity Framework

SQL can not understand the Difference function written in c#. To make it work you will have to fetch values from Products table in a c# collection like List
Then do ordering on that list using Difference function

Related

EF Core Views and SQL Parameters

I have created a view on SQL Server which produces a report for monthly totals. The view has been added to my DB Context and mapped successfully, therefore I am in a position where I can successfully get the results of my view as follows:
var list = db.MonthlyTotals.ToList();
However, I need to be able to restrict between dates and therefore needs to pass in some parameters for a start and end date.
Is this possible with either EF Core 6 or 7? Or do I need to use stored procedures instead?
I have created a view...I need to be able to restrict between dates and therefore needs to pass in some parameters for a start and end date...Is this possible with either EF Core 6 or 7?
Views don't use parameters, that's by design of the SQL Server Engine, and has nothing to do with whatever ORM you use, such as EF Core. If you really want to use parameters, then use stored procedures.
But the good news is, your use case is simple enough that you shouldn't need parameters anyway. Like Gert suggested in the comments, just use a Where clause against your view instead.
You can achieve this in C# with LINQ's method syntax like so:
var list = db.MonthlyTotals
.Where(mt => mt.YourDateColumn >= someDateVariable && my.YourDateColumn < someOtherDateVariable)
.ToList();
There's also query syntax with LINQ, which more closely resembles T-SQL code, but in my opinion is less intuitive in the context of C# as opposed to method syntax.

SQL Server extended events: write custom predicates?

We have about 2'000 "old" objects in a sql server database (tables, views etc.) of which we don't really know if they're still in use. I want to create an extended event listener for these objects. I tried to add a giant WHERE clause to the CREATE EVENT SESSION command, consisting of 2'000 [package0].[equal_int64]([object_id], (<objectId>)) statements.
However, the command max length is 3'000 characters, so I cannot do this. And I guess that the performance of this filer wouldn't be too good, anyway...
Now my question is: I can query all possible predicates using select * from sys.dm_xe_objects where object_type= 'pred_compare'. this gives me results such as name=equal_uint64, package_guid=60AA9FBF-673B-4553-B7ED-71DCA7F5E972. the package_guid refers to sys.dm_xe_packages, where several DLLs are referenced which seem to implement a particular predicate.
Would it be possible to define my own "package" and implement a predicate there (which would filter the objectId using a hashtable)? Is it possible somehow to import such a package into SQL server so I could define a custom predicate?
Or does anyone have another idea how to implement such a filter?

Does Dapper request a full object from the database prior to Linq operations?

I having been curious for awhile about how Dapper (or perhaps other ORMs) handle object retrieval when combined with LINQ.
If I have a class like this:
public static IEnumerable<SitePage> GetAll()
{
using (IDbConnection cn = new SqlConnection(g.Global.CONX))
{
cn.Open();
return cn.GetAll<SitePage>();
}
}
and I construct a query like this:
var result = SitePage.GetAll().Select(c=> new { c.id, c.PageUrl, c.ParentId });
I am curious if in the background, the entire record set gets pulled in including all the other columns (which may contain really big varchars), or does Dapper understand from this query only to pull in the columns I request from the sql db? I realize it's sort of newbish, but I want to better understand the Dapper/LINQ interaction.
A similar question was posted here: selecting-specific-columns-using-linq-what-gets-transferred, though I wasn't sure if was fully answered. The poster had 2 questions, and also wasn't using lambda expressions which I generally prefer.
The answer to this will set my mind afire (and quite possibly change the way I am coding, as I have been cautious and feel I am writing too much code via explicit sql).
Dapper doesn't transform your lambda expressions into SQL, so in your case the SQL query that Dapper generates returns full instances of SitePage.
A quick way to know if that's the case if have a look at the signature of Dapper's GetAll<T> method. As it returns IEnumerable<T>, it means that it returns a collection of T, so any operator you use after that - like Select in your case - will be applied to the full collection. In short, you're no longer in Dapper world after calling GetAll<T>.
If you used in the past fully-fledged ORMs - by that I mean with more capabilities, not necessarily better - like Entity Framework or NHibernate, you'll notice that some APIs return IQueryable<T>, which represents a query that has not yet been executed. So the operators you use on an IQueryable<T>, like Select and Where, actually modify the query. When you materialise the query by iterating it or calling ToList or ToArray on it, then the ORM transforms your query expression tree into SQL and sends that query to the database.

Multimapping in Dapper Without Custom SQL

Is there a way to use multimapping in Dapper in a generic way, without using custom SQL embedded in C# code?
See for example
Correct use of Multimapping in Dapper
Is there a generic way to query the data from 2 related entities, where common fields are determined automatically for join?
Don't do this. Don't even think this way! Databases are long lasting and normalized. Objects are perishable and frequently denormalized, and transitioning between the two is something to do thoughtfully, when you're writing your SQL. This is really not a step to automate. Long, painful experience has convinced many of us that database abstractions (tables and joins) should not just be sucked into (or generated out of) code. If you're not yet convinced, then use an established ORM.
If, on the other hand, you absolutely want to be in control of your SQL, but its the "embedding" in string literals in C# that bugs you, then I couldn't agree more. Can I suggest QueryFirst, a visual studio extension that generates the C# wrapper for your queries. Your SQL stays in a real SQL file, syntax validated, DB references checked, and at each save, QueryFirst generates a wrapper class with Execute() methods, and a POCO for the results.
By multi-mapping, I presume you want to fill a graph of nested objects. A nice way to do this is to use one QueryFirst .sql per class in your graph, then in the partial class of the parent, add a List of children. (QueryFirst generated POCOs are split across 2 partial classes, you control one of them, the tool generates the other.)
So, for a graph of Customers and their orders...
In the parent sql
select * from customers where name like #custName
The child sql
select * from orders where customerId = #customerId
In the parent partial class, for eager loading...
public List<Orders> orders;
public void OnLoad()
{
orders = new getOrders().Execute(customerId); // property of the parent POCO
}
or for lazy loading...
private List<Orders> _orders;
public List<Orders> orders
{
get
{
return _orders ?? _orders = new GetOrders().Execute(customerId);
}
}
5 lines of code, not counting brackets, and you have a nested graph, lazy loaded or eager loaded as you prefer, the interface discoverable in code (intellisense for the input parameter and result). Their might be hundreds of columns in those tables, whose names you will never need to re-type, and whose datatypes are going to flow transparently into your C#.
Clean separation of responsibilities. Total control. Disclaimer : I wrote QueryFirst :-)
Multimapping with Dapper is a method of running multiple SQL queries at once and then return each result mapped to a specific object.
In the context of this question, Multimapping is not even relevant, re: you're asking for a way to automatically generate a SQL query from the given objects and creating the correct joins which would result in a single SQL query which is not related to Multimapping.
I suspect what you're looking for is something along the lines of the Entity Framework. There are a couple of Dapper extension projects you may want to look into which will generate some of your SQL. See: Dapper.Rainbow VS Dapper.Contrib

Linq vs. database views

Here’s an interesting question. Suppose we have related tables in the database, for example, Instrument and Currency. Instrument table has a currency_id field that is mapped to entry in Currency table. In Linq land what’s the better way:
a) Create Instrument and Currency entities in the DataContext and then create association or simply use join in Linq queries or
b) Create a view in the database that joins Instrument and Currency (thus resolving currency_id to currency code) and use that as an entity in Linq context?
Would you ever use them independently? If so, you will need to have entities for each one that will be used independently. I suspect that you will use the Currency independently (say for a dropdown that allows you to choose a currency when creating an instrument). That being the case, I think it would be easier to just keep them separate and have an association.
With the ORM now abstracting the data access logic that particular function of views is no longer needed. It would be best to leave it to the ORM since thats part of its function.
However views may still be useful to simplify stored procedures code and even for creating useful indices.
If you load in Instrument and later use the Currencies property to load in related Currencies, there will be two queries.
If you issue a linq query with a join, linq will convert that to sql with a join and you get all the data at once.
If you set up a DataLoadOptions, you get all the data in one query and you do not have to write the join.
http://msdn.microsoft.com/en-us/library/system.data.linq.dataloadoptions.aspx
http://msdn.microsoft.com/en-us/library/system.data.linq.dataloadoptions.loadwith.aspx
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Instrument>(i => i.Currencies)
myDataContext.LoadOptions = dlo;
I find LINQ to be temperamental. I can run the same query 1 minute apart and get a different result. Note I am working of a local database so I know the data hasn't changed. Using a view with a dataset is far more reliable in my option, especially with joins.

Resources