String case sensitive in LiteDB query - litedb

In various environment, the user name is case insensitive. We query admin equal to ADMIN. I have searched LiteDB called CompareTo to compare two objects that I can't find a point to make string compared as case insensitive.
The code in QueryEquals.cs
internal override IEnumerable<IndexNode> ExecuteIndex(IndexService indexer, CollectionIndex index)
{
var node = indexer.Find(index, _value, false, Query.Ascending);
if (node == null) yield break;
yield return node;
if (index.Unique == false)
{
// navigate using next[0] do next node - if equals, returns
while (!node.Next[0].IsEmpty && ((node = indexer.GetNode(node.Next[0])).Key.CompareTo(_value) == 0))
{
if (node.IsHeadTail(index)) yield break;
yield return node;
}
}
}
The propositional we can case insensitive
using (var db = new LiteRepository("lite.db"))
{
db.Insert(new User { Name = "John" });
var user = db.Query<User>()
.Where(x => x.Name == "JOHN")
.FirstOrDefault(); // proposal return John
var fail = db.Query<User>()
.Where(x => string.Equals(x.Name, "JOHN", StringComparison.OrdinalIgnoreCase))
.FirstOrDefault(); // throw exception
}
Another consideration, it is a possible to execute lambda expression in LiteDB without conversion by visitor?

In LiteDB v4, you can use expressions to make sure that the index of username is stored as lowercase, then you can perform a "lowercase-compare"
// Create index
entity.EnsureIndex(e => e.Username, "LOWER($.Username)");
...
// Find user
collection.Find(e => e.Username == username.ToLower);
If you dont want to use expressions, I guess that you could make sure the username is lowercase before saving in LiteDB or you can use an index less query (slower) by using collection.Where (not quite sure on that method though).

Related

How to sort on DB side, if entities are not connected via Navigation (since it's not possible)

I want to have my EfCore query translated into the following SQL query:
select
c.blablabla
from
codes c
left join lookups l on c.codeId = l.entityid and l.languageCode = <variable - language code of current thread> and l.lookuptype = 'CODE'
where
..something..
order by
l.displayname
Note: tables 'codes' and 'lookups' are not connected! 'lookups' contains a lot of different lookup data in different languages!
I am stuck into limitations of EfCore (like 'NavigationExpandingExpressionVisitor' failed). I don't want to make in-memory filtering, it looks silly to me... Am I missing something obvious?
In perspective, I'd like to make universal method to help sort by displayname (or other lookup name) for different kind of entities - not only codes.
Seems like I figured it out. If there's a better approach - please let me know:
protected override IQueryable<FixCode> SortByDisplayName(IQueryable<FixCode> queryable, string languageCode = null)
{
return queryable
.GroupJoin(
DbContext.FixCodeValues.Where(x =>
x.DomainId == CentralToolConsts.Domains.CENTRAL_TOOLS
&& x.CodeName == CentralToolsFieldTypes.CODE_ORIGIN
&& (x.LanguageCode == languageCode || x.LanguageCode == CentralToolsDbLanguageCodes.English)),
//TODO: this will be a 'selector' parameter
code => code.CodeOriginId,
codeOrigin => codeOrigin.StringValue,
(c, co) => new
{
Code = c,
CodeOrigin = co
}
)
.SelectMany(
x => x.CodeOrigin.DefaultIfEmpty(),
(x, codeOrigin) => new { Code = x.Code, CodeOrigin = codeOrigin }
)
.OrderBy(x => x.CodeOrigin.ShortName)
.Select(x => x.Code);
}

EF Core entity refresh

I would like if there is a way to trigger an object hierachy's lazy load after it has been added in the cache following an insert.
If I insert an object only providing it the foreign keys ids and try to request it right after, none of these properties / collections are retrieved.
Example:
_dbContext.Set<MYTYPE>().Add(myObject);
await _dbContext.SaveChangesAsync(ct);
_dbContext.Entry(myObject).Collection(c => c.SomeCollection).Load();
_dbContext.Entry(myObject).Reference(c => c.Property1).Load();
_dbContext.Entry(myObject.Property1).Reference(c => c.NestedProperty).Load();
_dbContext.Entry(myObject).Reference(c => c.Property2).Load();
_dbContext.Entry(myObject).Collection(c => c.SomeCollection2).Load();
_dbContext.Entry(myObject).Reference(c => c.Property3).Load();
_dbContext.Entry(myObject).Reference(c => c.Property4).Load();
_dbContext.Entry(myObject.Property4).Reference(c => c.SomeOtherNestedProperty).Load();
_dbContext.Entry(myObject).Reference(c => c.Property5).Load();
_dbContext.Entry(myObject).Reference(c => c.Property6).Load();
return _dbContext.Set<MYTYPE>().Where(x => x.Id == myObject.Id);
Unless I do all the Load() (having to nest into several layers sometimes ...), I can't have any of the sub properties properly lazy loaded.
Note: doing
_dbContext.Entry(myObject).Reload()
or
_dbContext.Entry(myObject).State = EntityState.Detached;
doesn't work.
Any idea? Because I have several cases like this, with HEAVY object nesting, and it feels really bad to have to do all the loads manually.
Thanks.
The thing is, if you try to add some line using only the integer as a foreign key like below :
db.tablename.Add(new tablename{
name = "hello",
FK_IdofanotherTable = 5
});
db.SaveChanges();
Then entity does not care about linking the object immediately, you won't be able to access the linked object as a property.
This is how it's actually done in modern Entity Framework :
var TheActualCompleteObject = db.AnotherTable.First(t => t.id == 5);
db.tablename.Add(new tablename{
name = "hello",
AnotherTable = TheActualCompleteObject
});
db.SaveChanges();
So... basically, you will have loaded the object anyway, it's not gonna make anything faster, but it will be more consistant. You will be able to navigate through foreign keys properties.
If this is not possible, then you will have to query back AFTER SaveChanges to retrieve your object AND have access to foreign properties (eagerly loading them, of course, or else it's the same disaster)
Exemple :
_dbContext.Configuration.LazyLoadingEnabled = false;
_dbContext.Set<MYTYPE>().Add(myObject);
await _dbContext.SaveChangesAsync(ct);
var v = _dbContext.First(t => t.id == myObject.id);
var fk_prop = v.Property1;
I also found no easy way around this.
The following might make it simpler...
public static void Reset(this DbContext context)
{
var entries = context.ChangeTracker
.Entries()
.Where(e => e.State != EntityState.Unchanged)
.ToArray();
foreach (var entry in entries)
{
switch (entry.State)
{
case EntityState.Modified:
entry.State = EntityState.Unchanged;
break;
case EntityState.Added:
entry.State = EntityState.Detached;
break;
case EntityState.Deleted:
entry.Reload();
break;
}
}
}
Hope this helps!
JS

Why does this query always return ALL records?

I'm using WCF RIA in a Lightswitch project to create some query results. This query brings back all results regardless. I cannot make it filter the records based on the parameter passed (string Town).
public IQueryable<Enquiries> TestQuery(string Town)
{
List<Enquiries> riaenqs = new List<Enquiries>();
var enqs = this.Context.ClientEnquiries
.Include("Client")
.Include("Client.Town")
.OrderBy(enq => enq.Id);
if (Town != null)
{
enqs.Where(enq => enq.Client.Town.TownName == Town);
}
foreach (ClientEnquiry item in enqs.ToList())
{
Enquiries enq = new Enquiries();
enq.Id = item.Id;
enq.ClientName = item.Client.FirstName + " " + item.Client.Surname;
enq.Town = item.Client.Town != null ? item.Client.Town.TownName : null;
riaenqs.Add(enq);
}
return riaenqs.AsQueryable();
}
During debugging I can see that the Town is correctly populated and I can see that the query is built accordingly if Town is not null. However, when I hit the foreach statement where the linq to ef query is executed I always get all the results. I just cannot figure out where I'm slipping up.
The LINQ methods like the Where do not modify the collection/expression but always returning a new one.
So you need to reassign the result of the Where to your original variable enqs:
if (Town != null)
{
enqs = enqs.Where(enq => enq.Client.Town.TownName == Town);
}

declare variable to store linq entity for conditional statements

I am trying to look up record using if I have the key then use Find if not use Where
private ApplicationDbContext db = new ApplicationDbContext();
public bool DeactivatePrice(int priceId = 0, string sponsorUserName = "")
{
var prices = db.BeveragePrices;
// if we have an id then find
if (priceId != 0)
{
prices = prices.Find(priceId);
}
else
{
prices = prices.Where(b => b.UserCreated == sponsorUserName);
}
if (prices != null)
{
// do something
}
return true;
I get the following error for
prices = prices.Find(priceId);
Cannot convert app.Model.BeveragePrices from system.data.entity.dbset
I am copying the pattern from this answer but something must be different.
Seems you forgot to put a predicate inside the Find function call. Also you need to do ToList on the collection. The second option is a lot more efficient. The first one gets the whole collection before selection.
Another note commented by #Alla is that the find returns a single element. So I assume another declaration had been made for 'price' in the first option I state down here.
price = prices.ToList.Find(b => b.PriceId == priceId);
Or
prices = prices.Select(b => b.PriceId == priceId);
I assume the field name is PriceId.

Entity Framework - ElementAt

I have a Table User(ID, Name....), Projects(ID, Name, Timestamps, IsFavorite...), Projects_Favoite(UserID, ProjectID)
I try to check for each projekt if there is a row for the current user. If there is a row I want set the "IsFavorite" in my Project true, otherwise false.
I tied:
for(int i = 0; i <= erg.Count();i++)
{
if (erg.ElementAt(i).User11.Any(u => u.Guid == ID) == true)
erg.ElementAt(i).SetFavorite = true;
}
but there is no way to use ElementAt, because it can't translated to SQL.
So I tried:
for(int i = 0; i <= erg.Count();i++)
{
if (erg.Take(i).Last().User11.Any(u => u.Guid == ID) == true)
erg.Take(i).Last().SetFavorite = true;
}
same problem here, so I tried:
foreach (Project project in erg)
{
if (project.User11.Any(u => u.Guid == ID))
project.SetFavorite = true;
}
There is the same problem. Is there a way to realise a ElementAt?
You should be able to do:
foreach (Project project in erg.Where(p => p.User11.Any(u => u.Guid == ID))
.ToList())
project.SetFavorite = true;
}
Assuming that erg is an IQuerable than you cannot use ElementAt as it is not supported (http://msdn.microsoft.com/en-us/library/bb399342.aspx check the section Operators With no translation), you can use it on a list though, but of course you will lose the benefits of the deferred query.
Try to use Skip instead
var whatyouwant = erg.Skip(index).First();
By looking at the stacktrace (can't read german though) looks there's something wrong with the SetFavorite column. Try first to remove this bit first:
project.SetFavorite = true;
then check also that your model columns match with what you got on the db.