I have a model with startDate and endDate Property.
When inserting the model to mongo, the datetime is translated to ISO format datetime string.
I am trying to get document by dates range properties using LINQ on collection as documented at mongodb documentation https://mongodb-documentation.readthedocs.io/en/latest/ecosystem/tutorial/use-linq-queries-with-csharp-driver.html#gsc.tab=0
My C# code model relevant props:
public DateTime StartWorkDate { get; set; }
public DateTime FinishWorkDate { get; set; }
mongodb document relevant props:
My code where i try to get document by dates range
GetRecordsByDate(DateTime start,DateTime end){
...
var collection = _db.GetCollection<TestModel>("TestCollection");
var query = from test in collection.AsQueryable<TestModel>()
where (DateTime.Compare(test.StartWorkDate, start) > 0 || DateTime.Compare(test.StartWorkDate, start) == 0) &&
(DateTime.Compare(test.FinishWorkDate, end) < 0 || DateTime.Compare(test.FinishWorkDate, end) == 0)
select test;
return query.ToList();
}
I get the following exception:
Message:System.InvalidOperationException: 'Compare({document}{StartWorkDate}, 01/01/2019 00:00:00) is not supported
If i try get all documents and then run the same query on the result it works perfect:
GetRecordsByDate(DateTime start,DateTime end){
...
var collection = _db.GetCollection<TestModel>("TestCollection");
var resTemp = collection.Find(Builders<TestModel>.Filter.Empty).ToList();
var collectionResult = resTemp.Where(test =>
(DateTime.Compare(test.StartWorkDate, start) > 0 || DateTime.Compare(test.StartWorkDate, start) == 0) &&
(DateTime.Compare(test.FinishWorkDate, end) < 0 || DateTime.Compare(test.FinishWorkDate, end) == 0)
).ToList();
}
Which brings me to my other question (its just a good to know question):
I know its better using query on the mongo because its querying system is very efficient, But what is the difference between running the query on mongo then getting all documents and then running linq on them as i did at my working code
Managed to solve it using filters, Im sure someone will find it usefull
var collection = _db.GetCollection<TestModel>("TestCollection");
var builder = Builders<TestModel>.Filter;
var filter = builder.Gt(t => t.StartWorkDate, start) & builder.Lt(t => t.FinishWorkDate, end);
var res = collection.Find(filter).ToList();
Related
I'm trying to update two entities at the same time but the change is not applying and I think that when I try to return the update entity it doesn't even found it.
Here is my Razor view:
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
repositorioFamiliar.Actualizar(Familiar);
return RedirectToPage("/Familiares/DetalleFamiliar", new { IdPaciente = Familiar.IdPaciente });
}
Here is my update function:
public FamiliaresPer Actualizar(FamiliaresPer familiar)
{
var familiarActualizar = (from f in _context.Familiars.Where(p => p.IdFamiliar == familiar.IdFamiliar) select f).FirstOrDefault();
if (familiarActualizar != null)
{
familiarActualizar.Correo = familiar.Correo;
_context.Update(familiarActualizar);
_context.SaveChanges();
}
var personaActualizar = (from p in _context.Personas.Where(p => p.Id == familiar.IdPersona) select p).FirstOrDefault();
if (personaActualizar != null)
{
personaActualizar.Telefono = familiar.Telefono;
_context.Update(personaActualizar);
_context.SaveChanges();
}
var familiares = from p in _context.Familiars
from p1 in _context.Personas
where p.IdPaciente == familiar.IdPaciente
where p.IdPersona == p1.IdPersona
select new FamiliaresPer()
{
IdFamiliar = p.IdFamiliar,
IdPaciente = p.IdPaciente,
IdPersona = p1.IdPersona,
Id = p1.Id,
Nombres = p1.Nombres,
Apellidos = p1.Apellidos,
Genero = p1.Genero,
Telefono = p1.Telefono,
Parentesco = p.Parentesco,
Correo = p.Correo,
};
FamiliaresPer familiaresPer = familiares.FirstOrDefault();
return familiaresPer;
}
When I submit the form I get an error
NullReferenceException: Object reference not set to an instance of an object
And the link shows the IdPaciente = 0 when it should use the same IdPaciente of the updated entity (which the Id never changes).
In your OnPost( ) Action Method, you used repositorioFamiliar.Actualizar(Familiar);
but it looks like you didn't define 'Familiar'.
In addition, when I look at your code. I can give you an advice. Let's say your first update was done correctly and you got an error in the second update case. But you want both to be updated at the same time. Assume that the first object is updated in the database but the second one isn't. This is a problem, right? Unit of Work design pattern is very useful to solve this.
In brief, The approach should be to do SaveChanges() after both update processes are completed so there will be no changes in the database until both updates are completed.
So i am trying to retrieve an instance of the class "Sugar" for a specific date using this method in my UserDatabse.cs class:
public List<Sugar> GetSugarDate(DateTime dt)
{
var bld = database.Table<Sugar>().Where(mi => mi.Time.Date == dt.Date).ToList();
return bld;
}
*Keep in mind that the app doesn't have any instance of Sugar at the moment so the Date comparison is between a null and an actual date. I think that is causing the error, any solution would be appreciated.
The call to this method is made like this in another class:
DateTime Time = DateTime.Now;
ObservableCollection<Image> Sugar_Count = new ObservableCollection<Image>();
Image s = new Image();
s.Source = "drawable/soda.png";
var xa = App.Database.GetSugarDate(Time);
The class Sugar.cs is defined as follows:
public class Sugar
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public DateTime Time { get; set; }
public int DrinkCount { get; set; }
public Sugar()
{
Time = DateTime.Now;
DrinkCount = 0;
}
}
Now the error is get is as follows:
System.NotSupportedException: Member access failed to compile expression at SQLite.TableQuery'1[T].CompileExpr(System.Linq.Expressions.Expression expr, System.Collections.Generic.List'1[T]queryArgs)[0x006cc]in <9b4aaa861238418bec74a2ddde70f09>:0 at SQLite.TableQuery'1[T].CompileExpr(System.Linq.Expressions.Expression expr, System.Collections.Generic.List'1[T]queryArgs)[0x0009d]in <9b4aaa861238418bec74a2ddde70f09>:0 at SQLite.TableQuery'1[T].CompileExpr(System.Linq.Expressions.Expression expr, System.Collections.Generic.List'1[T]queryArgs)[0x0005f]in <9b4aaa861238418bec74a2ddde70f09>:0 at SQLite.TableQuery'1[T].CompileExpr(System.Linq.Expressions.Expression expr, System.Collections.Generic.List'1[T]queryArgs)[0x00008]in <9b4aaa861238418bec74a2ddde70f09>:0 at
System.Collections.Generic.List'1[T]..ctor(System.Collections.Generic.IEnumerable'1[T]collection)[0x00062] in /Users/builder/jenkins/workspace/xamarin-android/external/mono/mcs/class/referencesource/generic/list.cs:98 .....
The error occurs at this specific line:
var bld = database.Table<Sugar>().Where(mi => mi.Time.Date == dt.Date).ToList();
Where am i going wrong?
This part of the expression can not be translated to SQL.
mi => mi.Time.Date
You can try using:
var bld = database.Table<Sugar>().ToList().Where(mi => mi.Time.Date == dt.Date).ToList();
Accessing to the Date part of a DateTime column (mi.Time.Date) can not be translated to SQL using Linq, for this reason, your statement failed initially. So, using ToList fetches all records in memory allowing us to query with Linq to Object method not Linq to SQLite.
Its a little janky, but I have got this to work:
public List<Sugar> GetSugarDate(DateTime dt)
{
var dayStart = dt.Date.AddDays(-1);
var dayEnd = dt.Date.AddDays(1);
var bld = database.Table<Sugar>().Where(mi => mi.Time > dayStart && mi.Time < dayEnd).ToList();
return bld;
}
Also make sure you initialize your database connection with:
SQLiteConnection database = new SQLiteConnection(_path,false);
If you are querying a nullable DateTime
The little janky code worked for me
var dayStart = stockDate.Date.AddDays(-1);
var dayEnd = stockDate.Date.AddDays(1);
return db.Table<ProductStock>().Where(x => x.StockDate > dayStart && x.StockDate < dayEnd).ToListAsync();
I am looking for a good way to implement paging in ormlite and I found another question, which has this snippet:
var data = db.Select<address>(predicate).Skip((int) pageNumber).Take((int) pageSize).ToList();
Problem with the above is that it gets back all the results and then does the skip and take on it which defeats the purpose of paging.
At another google groups post I have found the same problem and a sample in a github issue is mentioned as a solution but the URL no longer works. Does anyone know how to correctly page using servicestack?
Found the answer in ormlite's tests. Essentially we could use SqlExpressionVisitor's Limit() like this:
var result = db.Select<K>( q => q.Where(predicate).Limit(skip:5, rows:10 ) );
I built a higher-level wrapper if you prefer working with Page and PageSize:
public static class PagingExtensions
{
public static SqlExpression<T> Page<T>(this SqlExpression<T> exp, int? page, int? pageSize)
{
if (!page.HasValue || !pageSize.HasValue)
return exp;
if (page <= 0) throw new ArgumentOutOfRangeException("page", "Page must be a number greater than 0.");
if (pageSize <= 0) throw new ArgumentOutOfRangeException("pageSize", "PageSize must be a number greater than 0.");
int skip = (page.Value - 1) * pageSize.Value;
int take = pageSize.Value;
return exp.Limit(skip, take);
}
// http://stackoverflow.com/a/3176628/508681
public static int? LimitToRange(this int? value, int? inclusiveMinimum, int? inclusiveMaximum)
{
if (!value.HasValue) return null;
if (inclusiveMinimum.HasValue && value < inclusiveMinimum) { return inclusiveMinimum; }
if (inclusiveMaximum.HasValue && value > inclusiveMaximum) { return inclusiveMaximum; }
return value;
}
}
Then you can write your query as:
var results = Db.Select<K>(predicate.Page(request.Page, request.PageSize));
Or, using the additional helper method to keep Page and PageSize to sensical and (possibly) performant values:
var results = Db.Select<K>(predicate.Page(request.Page.LimitTo(1,null) ?? 1, request.PageSize.LimitTo(1,100) ?? 100);
Which will enforce reasonable limits on Page and PageSize
I am using the following code to first check if a string is located somewhere within a column in my database. If it is, I am then needing to check if a few additional criteria are met by looking at different parts of the database (can be seen in the code below). I am not sure if this is an efficient method for doing this or if there is a much simpler way:
(from my Controller)
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
ViewBag.code = code;
// Need to check if this code is active
var order = db.Orders.SingleOrDefault(
o => o.OrderCode == code
&& o.Active == true);
if (order == null)
{
//Invalid
}
else
{
var orderIdent = db.OrderDetails.SingleOrDefault(
p => p.OrderDetailId == order.OrderId);
var barIdent = db.Drink.SingleOrDefault(
q => q.EstablishmentsID == orderIdent.DrinksId);
var barName = db.Establishment.SingleOrDefault(
r => r.EstablishmentsId == barIdent.EstablishmentsID);
ViewBag.barId = barName.name;
ViewBag.sample = order.Email;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar != barName.name)
{
//Not a match
}
else
{
//Match
}
}
return View();
}
Is this something to worry about? Is there a more efficient way of performing the actions that I am currently performing? Should I change the first table that is referenced to include data from the table I ultimately compare it to to avoid what seems to be an inefficient way of comparing information from different tables?
You should check the SQL query that gets generated. You can do that by e.g. outputting the queries to the console, which is done by setting db.Log = Console.Out;. There should be a similar method to output to the web page in your case. The lazy nature of LINQ makes things difficult to predict.
Other than that, you could make your life much easier if you create foreign key relationships between your tables, i.e. OrderDetails has Orders.OrderId as a FK. This will allow Entity Framework to generate navigational properties for your database. With them your code would look like this:
[HttpPost]
public ActionResult Index(FormCollection sampleKey)
{
string code = sampleKey["sampleCode"];
var detail = db.Orders.Where(o => o.OrderCode == code && o.Active == true)
.Select(o => new {
OrderCode = o.OrderCode,
BarId = o.Drink.Establishment.Select(n => n.name),
Sample = o.Email
})
.SingleOrDefault();
if (detail != null)
{
ViewBag.code = detail.OrderCode;
ViewBag.barId = detail.BarId;
ViewBag.sample = detail.Sample;
var custProfile = CustomProfile.GetUserProfile();
if (custProfile.OwnedBar == detail.BarId)
{
//Match
}
else
{
//Not a match
}
}
else
{
//Invalid
}
return View();
}
Hi I am looking for best method for writing Dynamic LINQ query.
I have a function like
public IQueryable<Student> FindByAllStudents(int? id, string Name, int? CourseID, bool? IsActive) // like this way, all field values are passed
{
// code for compairision
return db.Student;
}
we can also write db.Students.where(predicate)
or
a query like
var students = from s in db.students where s.Name.Contains(Name)
s.ID.Equals(id)
//and so on....
So will this method works if i don't pass ID (i.e. Null)?
is proper way for all the datatypes?
The point is function can have all null values as a parameter for equivalence of select * from statement.
can any one help me to build best query with sample code?
Okay, it's not entirely clear what you want, but if you're trying to only add where clauses for the parameters which are non-null, you could do:
public IQueryable<Student> FindByAllStudents
(int? id, string name, int? courseID, bool? isActive)
{
IQueryable<Student> query = db.Student;
if (id != null)
{
query = query.Where(student => student.ID == id.Value);
}
if (name != null)
{
query = query.Where(student => student.Name.Contains(name));
}
if (courseID != null)
{
query = query.Where(student => student.CourseID == courseID.Value);
}
if (isActive != null)
{
query = query.Where(student => student.IsActive == isActive.Value);
}
return query;
}
I haven't tried that, and it's possible that LINQ to SQL would get confused by the code to find the value of the nullable value types. You may need to write code like this:
if (courseID != null)
{
int queryCourseID = courseID.Value;
query = query.Where(student => student.CourseID == queryCourseID);
}
It's worth trying the simpler form first though :)
Of course, all this gets a bit irritating. A helpful extension method could make life more concise:
public static IQueryable<TSource> OptionalWhere<TSource, TParameter>
(IQueryable<TSource> source,
TParameter? parameter,
Func<TParameter, Expression<Func<TSource,bool>>> whereClause)
where TParameter : struct
{
IQueryable<TSource> ret = source;
if (parameter != null)
{
ret = ret.Where(whereClause(parameter.Value));
}
return ret;
}
You'd then use it like this:
public IQueryable<Student> FindByAllStudents
(int? id, string name, int? courseID, bool? isActive)
{
IQueryable<Student> query = db.Student
.OptionalWhere(id, x => (student => student.ID == x))
.OptionalWhere(courseID, x => (student => student.CourseID == x))
.OptionalWhere(isActive, x => (student => student.IsActive == x));
if (name != null)
{
query = query.Where(student => student.Name.Contains(name));
}
return query;
}
Using a higher order function like this could get confusing if you're not really comfortable with it though, so if you're not doing very many queries like this you might want to stick with the longer but simpler code.