Search for missing values ​in SQL Server table in C# - c#

Please tell me how to solve this problem.
Here is an example table:
Filled with data like this:
I have a method to automatically assign a number to the CerNambe column:
public string CerNamber()
{
var cer = DBContext.Certificate
.Where(p => p.CerNambe != null)
.OrderByDescending(p => p.Id)
.FirstOrDefault();
string _cer = cer.CerNambe;
int outCer = Convert.ToInt32(_cer.Substring(0, _cer.IndexOf('-')));
string newCer = Convert.ToString(outCer + 1 + "-P/" + DateTime.Now.Year);
return newCer;
}
But I ran into a problem. If the number is assigned by the user erroneously, it is deleted, and the numbering is violated.
Here is the question: how to find this violation and assign the missing number to the next record. But in this case, automatic numbering will not work? Since the method is looking for the last record!

How to find this violation and assign the missing number to the next record ?
If I were you, I would modify the database schema so that I don't have to do this. But if you have to, the easiest yet ugliest way is to use RegEx to filter and find special patterns.
The solution: If your underlying database provider is SQL Server, you could use SqlMethods.Like to filter the database result set down to a manageable subset of data that can then analyze locally with RegEx.
Linq to Entities doesn't support regex because it can't convert it to SQL. You could load all of the records back into memory and then use Linq to Objects on them (perform a. ToList() to a variable, then a second LINQ query for this regex), but this meant you'll get to load every DB record into memory to run this query.
The same advice applies: modify the database schema so that you don't have to do this.
For understanding RegEx visit :
System.Text.RegularExpressions.Regex Class

Related

Select Numeric Values From String Linq to Entities

I have records that have a string property called Project. The values these normally have are like A-A-40019-0 but in reality they could be anything.
I need to be able to extract the numeric values from the Project project property so that I can then try and cast it to a ulong so that it can be sorted by.
I'm trying the following code to select the number values from the Project property.
return jobs.Select(x => new JobViewModel
{
Sequence = x.Project.Where(y => char.IsDigit(y)).ToString()
});
When I try this I get the following error
DbExpressionBinding requires an input expression with a collection
ResultType.
I need to use Linq to Entities as I can't afford to load all records into memory.
I'm using SQL Server.
You don't say which DB you are using but I did find this for SQL Server. https://www.mytecbits.com/microsoft/sql-server/extract-numbers-from-string#:~:text=%20Extract%20Numbers%20From%20String%20In%20SQL%20Server,you%20want%20to%20split%20this%20delimited...%20More%20
Hopefully similar technique can be used for the DB you are using.
You could make a view with a column calling that function added on the end and then you can sort it.
or purely in C# which I haven't tried:
Convert.ToInt32(new string(y.project.Where(c => Char.IsDigit(c)).ToArray())

LINQ query to Azure SQL database timing out

I'm querying my sql database which is in Azure (actually my web app is on Azure as well).
Every time I perform this particular query, there are ever changing errors (e.g. sometimes timeout occurs, sometimes it works perfectly, sometimes it takes extremely long to load).
I have noted that I am using the ToList method here to enumerate the query but I suspect that's why it is degrading.
Is there anyway I can fix this or make it better....or maybe just use native SQL to execute my query?.
I should also note in my webconfig my Database connection timeout is set to 30 seconds. Would this have any performance benefit?
I'm putting the suspect code here:
case null:
lstQueryEvents = db.vwTimelines.Where(s => s.UserID == UserId)
.Where(s => s.blnHide == false)
.Where(s => s.strEmailAddress.Contains(strSearch) || s.strDisplayName.Contains(strSearch) || s.strSubject.Contains(strSearch))
.OrderByDescending(s => s.LatestEventTime)
.Take(intNumRecords)
.ToList();
break;
It's basically querying for the 50 records...I don't understand why it's timing out sometimes.
Here are some tips:
Make sure that your SQL data types matches types in your model
Judging by your code, types should be something like this:
UserID should be int (cannot tell for sure by looking at code);
blnHide should be bit;
strEmailAddress should be nvarchar;
strDisplayName should be nvarchar;
strSubject should be nvarchar;
Make use of indexes
You should create Non-Clustered Indexes on columns that you use to filter and order data.
In order of importance:
LatestEventTime as you order ALL data by this column;
UserID as you filter out most of data by this column;
blnHide as you filter out part of data by this column;
Make use of indexes for text lookup
You could make use of indexes for text lookup if you change your filter behaviour slightly and search text only in the start of column value.
To achieve that:
change .Contains() with .StartsWith() as it would allow index to be used.
create Non-Clustered Indexes on strEmailAddress column:
create Non-Clustered Indexes on strDisplayName column:
create Non-Clustered Indexes on strSubject column:
Try out free text search
Microsoft only recently have introduced full text search in Azure SQL. You can use that to find rows matching by partial string. This is a bit complicated to achieve using EF, but it is certainly doable.
Here are some links to get you started:
Entity Framework, Code First and Full Text Search
https://azure.microsoft.com/en-us/blog/full-text-search-is-now-available-for-preview-in-azure-sql-database/
string.Contains(...) converted to WHERE ... LIKE ... sql-statement. Which is very expensive. Try to reform your query to avoid it.
Plus, Azure SQL has it's own limitations (5 sec as far as I remember, but better check SLA) for query run, so it would generally ignore your web.config settings if they are longer.

How to get a correct result of binary string intersection in Entity to Linq query

I save my data in a binary-look string, "100010" ,for example. And I want to check whether it has same value in corresponding place with the other string "100000".
So I try to use "Intersection". In this Condition, the result of intersection will be "100000", and it could be seen as the item I need for my requirement. But how can I use this conception when I query a Entity to Linq statement?
Here is my thought:
var chemicals = db.ChemicalItem.Where(c => c.CategoryNumber.ToCharArray().Intersect(catekey.ToCharArray()).Count()>0);
"CategoryNumber" is my data, and "catekey" is the string for comparing. Both of them are binary-look string(cantain 6 chars). And if the count is not 0,they have '1's in the same index. And I can get the correct query.
Sadly, It didn't work. I always get DbExpressionBinding Error. Can somone tell me What's Wrong? Thanks.
PS:I'm not good at English and post the question here first time, sorry for my bad expression and thank for your reading.
LINQ to Entities is trying to create a SQL query out of your condition, but is not able to do it for the expression you specified.
One way to "fix" the problem would be to do the filtering in code instead of in SQL, but this will impact performance, because all of the records will be retrieved to the client and filtered there. This is how you could do it (notice the added ToList()):
var chemicals = db.ChemicalItem.ToList().Where(c => c.CategoryNumber.ToCharArray().Intersect(catekey.ToCharArray()).Count()>0);
A suggested way would be to do the filtering in SQL, but in this case you will need to write an equivalent stored procedure in SQL which will do the filtering and call that from your EF code. Still such filtering will not be very effective because SQL will not be able to use any indices and will always need to do a table scan.

Get last index of character with LINQ to Entities

I'm getting the error:
LINQ to Entities does not recognize the method 'Int32 LastIndexOf(System.String)'
method, and this method cannot be translated into a store expression.
When using this code to tell if a person's last name starts with certain characters:
persons = persons.Where(c => c.FullName.IndexOf(" ") > 0 &&
c.FullName.Substring(c.FullName.LastIndexOf(" ")+1).StartsWith(lastNameSearch));
Any clue how to achieve this without using LastIndexOf()? Maybe I have to check for this after I grab results from the database using ToList()?
You are limited by the set of canonical functions that can be translated into an SQL query, so any solution must be achieved with no more than the canonical functions offer.
Luckily, one of the supported functions is the bool Contains(string) instance method. You can rewrite your check as
persons = persons.Where(c => c.FullName.Contains(" " + lastNameSearch));
This is not exactly like your current version (because it will allow people with more than one name to match their second name, while the former won't), but it's pretty close and IMHO can be acceptable.
Of course it would be much better than any of this to keep the last names as a separate column in the database, if that is at all possible.

Entity Framework include vs where

My database structure is this: an OptiUser belongs to multiple UserGroups through the IdentityMap table, which is a matching table (many to many) with some additional properties attached to it. Each UserGroup has multiple OptiDashboards.
I have a GUID string which identifies a particular user (wlid in this code). I want to get an IEnumerable of all of the OptiDashboards for the user identified by wlid.
Which of these two Linq-to-Entities queries is the most efficient? Do they run the same way on the back-end?
Also, can I shorten option 2's Include statements to just .Include("IdentityMaps.UserGroup.OptiDashboards")?
using (OptiEntities db = new OptiEntities())
{
// option 1
IEnumerable<OptiDashboard> dashboards = db.OptiDashboards
.Where(d => d.UserGroups
.Any(u => u.IdentityMaps
.Any(i => i.OptiUser.WinLiveIDToken == wlid)));
// option 2
OptiUser user = db.OptiUsers
.Include("IdentityMaps")
.Include("IdentityMaps.UserGroup")
.Include("IdentityMaps.UserGroup.OptiDashboards")
.Where(r => r.WinLiveIDToken == wlid).FirstOrDefault();
// then I would get the dashboards through user.IdentityMaps.UserGroup.OptiDashboards
// (through foreach loops...)
}
You may be misunderstanding what the Include function actually does. Option 1 is purely a query syntax which has no effect on what is returned by the entity framework. Option 2, with the Include function instructs the entity framework to Eagerly Fetch the related rows from the database when returns the results of the query.
So option 1 will result in some joins, but the "select" part of the query will be restricted to the OptiDashboards table.
Option 2 will result in joins as well, but in this case it will be returning the results from all the included tables, which obviously is going to introduce more of a performance hit. But at the same time, the results will include all the related entities you need, avoiding the [possible] need for more round-trips to the database.
I think the Include will render as joins an you will the able to access the data from those tables in you user object (Eager Loading the properties).
The Any query will render as exists and not load the user object with info from the other tables.
For best performance if you don't need the additional info use the Any query
As has already been pointed out, the first option would almost certainly perform better, simply because it would be retrieving less information. Besides that, I wanted to point out that you could also write the query this way:
var dashboards =
from u in db.OptiUsers where u.WinLiveIDToken == wlid
from im in u.IdentityMaps
from d in im.UserGroup.OptiDashboards
select d;
I would expect the above to perform similarly to the first option, but you may (or may not) prefer the above form.

Categories

Resources