Combobox "Select All" in linq query - winforms

I have multiple comboboxes that pass a value to a linq query. Previously I was handling it with
if(combobox.text == "select all")
{combobox.text = "")
And then using the StartsWith(combobox.text) method to do the comparison, I know this is wrong. Since "jim" would return "Jimmy". How do I select all when "select all" is selected?

The best would be to conditionally add the query filter:
var query = dataSource.foo.AsQueryable();
//you may or may not need AsQueryable() depending on what "foo" is
//if it is not queryable, you may need AsEnumerable(), or simply nothing
if (!combobox.Text.Equals("select all"))
query = query.Where(x => x.Equals(combobox.Text));
return query.ToList();
The "simpler" way would be to use a boolean or, but the resulting query is uglier and may or may not be translatable to SQL (if that is what you are using):
var query = dataSource.foo
.Where(x => combobox.Text.Equals("select all") || x.Equals(combobox.Text));

Related

Using SqlKata from an existing Query

I have existing queries used for jobs that run within services to generate reports. Simple things like
"Select * from Transactions"
The jobs will then append parameters to these queries based on preset rules, like Date>Yesterday etc. SqlKata looks like it can do this but I'm not sure how to instantiate the Query object from an existing query. Is something like this possible?
Dim Qry as new Query("Select * from Transactions").OrderByDesc("Date")
Qry.Where("Date", ">", Date.Now().AddDays(-1))
return Qry.Get()
The closest thing that you can do in this case is to wrap the inner query and add conditions on top of it, you can use the SubQuery or CTE approach here.
Something like this, this in C# but the idea is the same.
var existingSql = "select * from transactions";
var query = new Query().FromRaw($"({existingSql}) as inner")
.Where("date", ">=", DateTime.UtcNow.Date);
checkout this example on playground

How can I use Entity Framework LINQ to find rows where a column starts with a string?

I am currently using this to query data in SQL Server:
var query = db.Phrases.AsQueryable();
if (options.Romaji != null) query = query
.Where(w => w.Romaji.Contains(options.Romaji));
How can I change this so that instead of looking for a row with a column with a string in it that it looks for a row with a column which starts with the string in options.Romaji?
You just need to use the StartsWith() method instead of contains.
query = query.Where(w => w.Romaji.StartsWith(options.Romaji));

Delete trigger for audit table

I'm working on a web application that executes CRUD operations on some table in a SQL Server database. There will be a logged user in the application executing these operations.
(By the way, I'm using Entity Framework)
Let's say table is
MyTable
MyTableId
SomeColumn
LastModifiedUserId
LastModifiedDate
And I a have an audit table like
MyTableHistory
MyTableHistoryId
MyTableId
SomeColumn
ActionType --ins/upd/del
ActionUserId
ActioDate
And I'm using triggers to insert data on the audit table.
Inserts and updates are easy by consulting the Inserted and Updated tables to find the userid who modified the record.
But what about deletes? Any idea how I might get that info?
There is no such thing as updated table. The two pseudo tables available in DML triggers are inserted and deleted. In the case of insert table deleted is empty, in the case of delete table inserted is empty, in the case of update both tables are populated.
You can create three separate triggers for each action (to distinguish ActionType) or try to combine all in one trigger.
Note: take into account multiple row actions.
Assuming you are using EF to add the information about which user is updating records, the easiest way to capture that information is to have EF perform a 2-step process (UPDATE, DELETE) on the data you wish to delete. You will then need to interpret the two audit rows as part of the same operation.
There is a much more involved solution that "might" work, but I have not tested it. There is more information available below if you wish to explore it.
Blog describing the solution
Stack Overflow post of someone trying it
Another option altogether is to abandon trigger auditing (which is problematic for this very reason) and use Entity Framework instead. Below is an example of how one might accomplish this by overriding the SaveChanges method:
public virtual IEnumerable<System.Data.Entity.Infrastructure.DbEntityEntry> ChangedEntries()
{
return ChangeTracker.Entries().Where(x =>
x.State == EntityState.Added ||
x.State == EntityState.Deleted ||
x.State == EntityState.Modified);
}
public virtual int SaveChanges(string userName)
{
var changes = ChangedEntries();
foreach (var entry in changes)
{
var eventType = entry.State == EntityState.Added ? "A" : entry.State == EntityState.Deleted ? "D" : "U";
var entityType = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
var oldValues = entry.State == EntityState.Added ? null : JsonConvert.SerializeObject(entry.OriginalValues.ToObject());
var newValues = entry.State == EntityState.Deleted ? null : JsonConvert.SerializeObject(entry.CurrentValues.ToObject());
oldValues = oldValues?.Substring(0, Math.Min(oldValues.Length, 4000));
newValues = newValues?.Substring(0, Math.Min(newValues.Length, 4000));
AuditItems.Add(
new AuditItem
{
EventTime = DateTime.Now,
UserName = userName,
EntityType = entityType,
EventType = eventType,
OldValues = oldValues,
NewValues = newValues
}
);
}
return base.SaveChanges();
}

Select 'N' rows and get number of rows using Entity Framework

Currently we have a page where we need pagination so for that i need 2 info
1. Get total number of rows
2. Fetch 'N' number of rows
Currently i am doing it with 2 query, for step 1 something like
count = db.Transactions
.AsNoTracking()
.Where(whereClause
.Count();
And then
db.Transactions
.AsNoTracking()
.Where(whereClause
.Skip(skipRows)
.Take(pagesize)
.ToList();
Is there is any way to optimize it?
You can try using Local Data:
// Load all Transactions with filtering criteria into the context
db.Transactions.AsNoTracking().Where(whereClause).Load();
// Get Count
var transcationsCount = db.Transactions.Local.Count;
// Paging
var pagedTranscations = db.Transactions.Local.Skip(skipRows).Take(pageSize).ToList();
This should only result in one database query being fired to the database in the initial Load() call.
This will return you an IQueryable and you can do queries against that, each will be executed to the db. This way you don't have to rewrite the query each time you want to query something.
var query = (from t in db.Transactions
where whereClause
select t);
var count = query.Count();
var items = query
.Skip(skipRows)
.Take(pagesize)
.ToList();

c++ builder: getting values via ADOQuery using SELECT

The question is as for delphi coders as for c++ builder coders, cuz I'm using the same components.
I'm trying to fill labels on the form by the data from database. I do a SELECT query via TADOQuery. But when I try to get a result, I always get an error like "ADOQuery1: Field 'count' not found".
'id' passed to the function is an autoincrement field value, which is EXACTLY exists in database (it was got via DBLookupComboBox). Also, executing the query manually to show result in DBGrid is successfull.
Querying without parameters and writing 'id' value to query string fails too.
What's the problem? Here's the code.
void TSellForm::LoadData(int id) {
TADOQuery* q = DataModule1->ADOQuery1;
q->Active = false;
try
{
q->SQL->Text = "select * from drugs where(id=:id)";
q->Parameters->ParamByName("id")->Value = IntToStr(id);
q->ExecSQL();
this->LabelAvail->Caption = q->FieldByName("count")->Value;
}
catch (Exception* e) {
MessageBox(NULL, PChar(WideString(e->Message)),
L"Exception", MB_OK|MB_ICONWARNING);
}
q->SQL->Clear();
}
ExecSQL is only used for SQL statements that don't return a recordset, and to determine the results you use RowsAffected.
For SELECT statements (which return a recordset), you use Open or set Active to true.
Also, count is a reserved word in most SQL dialects (as in SELECT Count(*) FROM ..., so if you have a column with that name you're going to need to escape it, typically by using either [] or double-quotes around it or by aliasing it in the SELECT itself.
ADOQuery1->Close();
ADOQuery1->SQL->Text= "SELECT * FROM reportTble WHERE (firstName =:firstName) " ;
ADOQuery1->Parameters->ParamByName("firstName")->Value = textBox->Text ;
ADOQuery1->Open();
This is how you can use ADOQuery

Resources