ServiceStack Ormlite SqlExpressionVisitor null check in Where extension - servicestack

I would like to write a method for querying table with one method by null cheking parameters using SqlExpressionVisitor of Ormlite
Here is my method :
public static List<UserChatsDTO> GetUserChats(int startRow, int rowCount, DateTime? startDate, DateTime? endDate, string operatorName, short? rating, string visitorName)
{
using (IDbConnection db = DbFactory.OpenDbConnection())
{
SqlExpressionVisitor<UserChatsDTO> ev = OrmLiteConfig.DialectProvider.ExpressionVisitor<UserChatsDTO>();
ev.Where(q =>
(startDate.HasValue && q.Dated >= startDate) &&
(endDate.HasValue && q.Dated <= endDate) &&
(!string.IsNullOrEmpty(operatorName) && q.TakenByUser.Contains(operatorName)) &&
(rating.HasValue && q.Rating == (short)rating) &&
(!string.IsNullOrEmpty(visitorName) && q.VisitorName.Contains(visitorName)));
//ev.OrderBy();
ev.Limit(startRow, rowCount);
return db.Select<UserChatsDTO>(ev);
}
}
But Object reference not set to an instance of an object. NullReferenceException is thrown when i call ev.Where part.
Is there a bug here or i am missing something ?
Thank you.

You can actually build up the ExpressionVisitor inside the Select method like so:
var chats = db.Select<UserChatsDTO>(q => q
.Where(x => startDate.HasValue && x.Date >= startDate)
.Where(x => endDate.HasValue && x.Date <= endDate)
.Where(x => string.IsNullOrEmpty(operatorName) || x.TakeByUser.Contains(operatorName))
.Where(x => rating.HasValue && x.Rating == (short)rating)
.Where(x => string.IsNullOrEmpty(visitorName) || x.VisitorName.Contains(visitorName)
.Limit(startRow, rowCount));

I know this question is 7 months old but I had a similar issue & this was the first question that came up when I searched. I wanted to add my working solution since Master Morality's didn't work for me.
Originally, I tried syntax roughly similar to mustafasturan's first attempt. I got the same NullReferenceException he did. Master Morality's answer did not help either...
I'm trying to build a search function that performs LIKE searches rather than exact match. There are multiple criteria on the request object which may or may not be null (for simplicity's sake we'll use an example with 2 criteria). Following Master Morality's suggestion, I tried this:
var searchResults = db.Select<Item>(q => q
.Where(x => string.IsNullOrWhiteSpace(request.Criteria1) || x.Criteria1.Contains(request.Criteria1))
.Where(x => string.IsNullOrWhiteSpace(request.Criteria2) || x.Criteria2.Contains(request.Criteria2))
);
I still got a NullReferenceException. Seems like the && and || operators are not using short-circuit evaluation inside the lambda expression.
What I finally had to go with is this:
SqlExpressionVisitor<Item> ev = new ServiceStack.OrmLite.MySql.MySqlExpressionVisitor<Item>();
if (!String.IsNullOrWhiteSpace(request.Criteria1)) {
ev.Where(q => q.Criteria1.Contains(request.Criteria1));
}
if (!String.IsNullOrWhiteSpace(request.Criteria2)) {
ev.Where(q => q.Criteria2.Contains(request.Criteria2));
}
searchResults = db.Select<Item>(ev);
It doesn't feel very elegant, but it's the only thing I could find that works.

Related

Collect all pickups while passing on the street for the first time in Jsprit

I'm trying to solve a simple TSP with Jsprit. I only have 1 vehicle and a total of about 200 pickups.
This is my vehicle routing algorithm code:
val vrpBuilder = VehicleRoutingProblem.Builder.newInstance()
vrpBuilder.setFleetSize(VehicleRoutingProblem.FleetSize.FINITE)
vrpBuilder.setRoutingCost(costMatrix)
vrpBuilder.addAllVehicles(vehicles)
vrpBuilder.addAllJobs(pickups)
val vrp = vrpBuilder.build()
val builder = Jsprit.Builder.newInstance(vrp)
val stateManager = StateManager(vrp)
val constraintManager = ConstraintManager(vrp, stateManager)
constraintManager.addConstraint(object : HardActivityConstraint {
override fun fulfilled(
context: JobInsertionContext?,
prevActivity: TourActivity?,
newActivity: TourActivity?,
nextActivity: TourActivity?,
previousActivityDepartureTime: Double
): HardActivityConstraint.ConstraintsStatus {
if (prevActivity !== null && newActivity !== null && nextActivity !== null && context !== null) {
if (prevActivity.location.id === nextActivity.location.id) {
return HardActivityConstraint.ConstraintsStatus.FULFILLED
}
val distanceBetweenPrevAndNew = costMatrix.getDistance(
prevActivity.location,
newActivity.location,
prevActivity.endTime,
context.newVehicle
)
val distanceBetweenPrevAndNext = costMatrix.getDistance(
prevActivity.location,
nextActivity.location,
prevActivity.endTime,
context.newVehicle
)
if (distanceBetweenPrevAndNext > distanceBetweenPrevAndNew) {
return HardActivityConstraint.ConstraintsStatus.FULFILLED
} else {
return HardActivityConstraint.ConstraintsStatus.NOT_FULFILLED
}
}
return HardActivityConstraint.ConstraintsStatus.FULFILLED
}
}, ConstraintManager.Priority.CRITICAL)
builder.setProperty(Jsprit.Parameter.FAST_REGRET, true.toString())
builder.setProperty(Jsprit.Parameter.CONSTRUCTION, Construction.REGRET_INSERTION.toString())
builder.setProperty(Jsprit.Parameter.THREADS, threads.toString())
builder.setStateAndConstraintManager(stateManager, constraintManager)
val vra = builder.buildAlgorithm()
As routing cost i'm using a distance only FastVehicleRoutingTransportCostsMatrix built with the Graphhopper Matrix Api.
The vehicle should avoid passing in front of an uncollected pickup, I tried to set up an hard activity constraint that checks if the new inserted activity is further away than the next one. If it's not further away, the constraint is not fulfilled. However the constraint does not work quite well.
Here's an example of an optimized route with the constraint:
example
The correct order for my case should be: 46 43 45 44 , however Jsprit orders them in that way because after 44 the vehicle has to do an uturn and run through the street again to reach 47,48,49...
I'm not sure if setting up a constraint is the right way to solve this, do you have any advices?
Thanks

EF Core 3 evaluate navigation property null on server

I have a request
DbContext.Invoices
.Where(x => x.Status != InvoiceStatus.Draft && x.PaymentMethod == PaymentMethod.DirectDebit)
.Where(x => x.DirectDebitFile == null).ToList();
DirectDebitFile is a reverse navigation property.
Which was working fine in EF Core 2, not sure about how it was evaluated in the final request.
After upgrade to EF Core 3, this request doesn't work anymore and says
System.InvalidOperationException: The LINQ expression 'DbSet<Invoice>
.Where(i => !(i.IsDeleted))
.Where(i => i.ClubId == __CurrentUser_ClubId_0)
.Cast()
.Where(e => e.FederationId == __CurrentUser_FederationId_1)
.Cast()
.Where(e0 => !(e0.Hidden))
.Cast()
.Where(e1 => (int)e1.Status != 0 && (Nullable<int>)e1.PaymentMethod == (Nullable<int>)DirectDebit)
.LeftJoin(
outer: DbSet<DirectDebitFile>
.Where(d => !(d.IsDeleted)),
inner: e1 => EF.Property<Nullable<long>>(e1, "Id"),
outerKeySelector: d => EF.Property<Nullable<long>>(d, "InvoiceId"),
innerKeySelector: (o, i) => new TransparentIdentifier<Invoice, DirectDebitFile>(
Outer = o,
Inner = i
))
.Where(e1 => e1.Inner == null)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I can rewrite this query and make it work by moving evaluation to the client-side
DbContext.Invoices
.Include(x=>x.DirectDebitFile)
.Where(x => x.Status != InvoiceStatus.Draft && x.PaymentMethod == PaymentMethod.DirectDebit)
.AsEnumerable()
.Where(x => x.DirectDebitFile == null).ToList();
But in this case, of course, the query will pull up all the rows and filtering x.DirectDebitFile == null will be on the client-side. I want this query to be evaluated on the server, please help to achieve that.
Currently, I changed the request as the way as normal SQL check it, by checking one of the joined table field
AppDbContext.Invoices.Include(x => x.DirectDebitFile)
.Where(x => x.Status != InvoiceStatus.Draft)
.Where(x => x.DirectDebitFile.FileName == null);

NHibernate queryover how to apply date isbetween without including the from and todate

I am trying to write NHibernate queryover to select all records which has been deleted between two dates. I am using IsBetween().And(). But how do i write if i dont want to include both the fromdate and todate?
Here is my query:
public IEnumerable<DeletedRecord> Search(
DateTime deletedFrom,
DateTime deletedTo
)
{
DeletedRecord delAlias = null;
var query = Session.QueryOver(() => delAlias);
query.Where(() => delAlias.DeletedDate.IsBetween(deletedFrom).And(deletedTo));
return query.Future<DeletedRecord>();
}
Can anyone help me how to achieve so that i can bring all records after the deletedFrom date and before the deletedTo date?
Thanks
Just construct your date in 2 steps:
var query = Session.QueryOver(() => delAlias);
if(youNeedFromDate) //first step
query = query.Where(() => delAlias.DeletedDate >= deletedFrom);
if(youNeedToDate) //second step
query = query.Where(() => delAlias.DeletedDate <= deletedTo);
youNeedFromDate and youNeedToDate are bool variables that you can pass to your function or it could be different condition upon your logic.
Such cases happen quite often . defining extension method helps a lot. see below
public static IQueryOver<T, T> WhereIf<T>(this IQueryOver<T, T> query,bool condition, Expression<Func<T, bool>> expression) where T : class
{
if (condition)
{
query = query.And(expression);
}
return query;
}
Using the above you can chain you conditions and only it will only include the where condition if the first arg evaluates to true.
var query= Session.QueryOver<DeletedRecord>()
.WhereIf(filterByFrom,d=>d.DeletedDate>=fromDate)
.WhereIf(filterByTo,d=>d.DeletedDate<=toDate);

How i can get latest record by using FirstOrDefault() method

Suppose i have 2 records in data base
1) 2007-12-10 10:35:31.000
2) 2008-12-10 10:35:31.000
FirstOrDefault() method will give me the first record match in sequence like 2007-12-10 10:35:31.000 but i need the latest one which is 2008-12-10 10:35:31.000
if ((from value in _names where value != null select value.ExpiryDate < now).Any())
{
return _names.FirstOrDefault();
}
You can use:
return _names.LastOrDefault();
However, your if just sends another unnecessary query (and it is a wrong query too). If you don't have any record, LastOrDefault and FirstOrDefault will return null. You can use something like this to improve the code:
var name = _names.LastOrDefault();
if(name != null)
{
return name;
}
// other code here
If you really want to use FirstOrDefault, you should order descending, like:
var name = _names.Where(n => n.ExpiryDate < now).OrderByDescending(n => n.ExpiryDate).FirstOrDefault();

RIA DomainService IQueryable - Select

Following a couple different tutorials, I've been trying to build a "Silverlight Business Application" against a database I've created. I've found I have two problems. The one I'm asking about here is how to filter the query.
The query that is built in the DomainService is when using the VS2010 template is:
[EnableClientAccess]
public class ChargesService : LinqToEntitiesDomainService<ChargesEntities>
{
public IQueryable<tblChargeCode> GetCharges()
{
return ObjectContext.tblChargeCodes.OrderBy(e => e.Chrgs_Code_01).Take(10);
}
}
I'm trying to create another query against the same ObjectContext.tblChargeCodes. Pulling the entire table (30 columns by ~7k rows) creates a timeout error.
I can't figure out how to do a select. I want to select Charge_Codes_01 and Bill_Description with a "starts with" type functionality (dynamic drop down search functionality). I've tried different variations of this without success. Something just isn't clicking in my brain.
public IQueryable<tblChargeCode> SearchCharges(string num)
{
var min = System.Convert.ToInt32(num.PadRight(7, '0'));
var max = System.Convert.ToInt32(num.PadRight(7, '9'));
return ObjectContext.tblChargeCodes
.Select(e => e.Chrgs_Code_01, e.Chrgs_Code_01_Desc)
.Where(e => e.Chrgs_Code_01 >= min && e.Chrgs_Code_01 <= max)
.OrderBy(e => e.Chrgs_Code_01)
.Take(10);
}
(sorry for my bad english)
The problem with you code is the "Select" - your method signature says that it must return a IQueryable of tblChargeCode, so you cannot return a projection. Here is two ways you can write your query:
In the server:
public IQueryable<tblChargeCode> SearchCharges(int min, int max, string description)
{
return ObjectContext.tblChargeCodes
.Where(e => e.Chrgs_Code_01 >= min && e.Chrgs_Code_01 <= max)
.Where(e => e.Bill_Description.StartsWith(description))
.OrderBy(e => e.Chrgs_Code_01)
.Take(10);
}
And call it on the client:
context.Load(context.SearchChargesQuery(0, 9999999, "Bill"), (op) =>
{
//op.Entities has your entities loaded
}, null);
Or you can just leave the query on the server:
public IQueryable<tblChargeCode> GetCharges()
{
return ObjectContext.tblChargeCodes.OrderBy(e => e.Chrgs_Code_01);
}
And call it from the client (it will filter on the server)
context.Load(context.GetChargesQuery().Where(e => e.Chrgs_Code_01 >= 0 && e.Chrgs_Code_01 <= 9999999)
.Where(e => e.Bill_Description.StartsWith("Bill"))
.OrderBy(e => e.Chrgs_Code_01)
.Take(10), (op) =>
{
//op.Entities has your entities loaded
}, null);
You also can use "Contains" instead of "StartsWith" in your query.

Resources