Linq To NHibernate Plus sql user defined function - tsql

I have a rather large linq-to-nhibernate query. I now need to add a filter based on a user-defined function written in t-sql that i have to pass parameters into. In my case, I need to pass in a zipcode that the user types in and pass it to the t-sql function to filter by distance from this zip. Is this possible, or do i need to rewrite my query using the ICriteria api?

i did find a solution:
Note the NHibernate query (nquery) which has RegisterCustomAction:
private void CallZipSqlFunction(ListingQuerySpec spec, IQueryable<Listing> query)
{
var nQuery = query as NHibernate.Linq.Query<Listing>;
//todo: find some way to paramaterize this or use linq-to-nh and not criteria to call the function
// so i don thave to check for escape chars in zipcode
if (spec.ZipCode.Contains("'"))
throw new SecurityException("invalid character");
//yuck!
var functionString = "dbo.GetDistanceForListing('" + spec.ZipCode + "',{alias}.ID) as Distance";
//create a projection representing the function call
var distance = Projections.SqlProjection(functionString, new[] { "Distance" }, new IType[] { NHibernateUtil.String });
//create a filter based on the projection
var filter = Expression.Le(distance, spec.ZipCodeRadius.Value);
//add the distance projection as order by
nQuery.QueryOptions.RegisterCustomAction(x => x.AddOrder(Order.Asc(distance)));
//add teh distance filter
nQuery.QueryOptions.RegisterCustomAction(x => x.Add(filter));
}

Related

How to modify the available filter operators of a smart table

I have a smart table that shows data from odata service. all properties of the entity type are Edm.String.
now i can set a filter for each column of the resulting table with a lot of filter operators.
My goal is to filter the list of available filter operators depending on the selected column.
e.g.
selected colum 'A' then allow only 'equal to'.
Is that somehow possible? I would like to solve it in front end code.
I didn't find anything like that in ui5 docu...
you need to use equals FilterOperator
here is a link for FilterOperator and another example how to use filter in grid table https://sapui5.hana.ondemand.com/
Here is a quick example of setting more than one filter each with different Filter Operator
filterGlobally : function(oEvent) {
var sQuery = oEvent.getParameter("query");
this._oGlobalFilter = null;
if (sQuery) {
this._oGlobalFilter = new Filter([
new Filter("columA", FilterOperator.EQ, sQuery),
new Filter("columB", FilterOperator.Contains, sQuery)
], false);
}
var oFilter = null;
if (this._oGlobalFilter) {
oFilter = new Filter([this._oGlobalFilter], true);
}
this.byId("idTable").getBinding().filter(oFilter, "Application");

EF6 can I update model/table after lambda querying?

I am lambda querying models (I make projection with other classes-GameBankVM, GameCouponBankVM) and at the end, I would like to loop throuh query result and update the model field. But I am getting The entity or complex type 'EPINMiddleWareAPI.Models.GameBankVM' cannot be constructed in a LINQ to Entities query.
Here is my sample code:
var gameBankResult = await (context.GameBanks.Where(g => g.productCode == initiate.productCode)
.Take(initiate.quantity)
.Select(g => new GameBankVM
{
quantity = g.quantity,
currency = g.currency,
initiationResultCode = g.initiationResultCode,
productCode = g.productCode,
productDescription = g.productDescription,
referenceId = g.referenceId,
responseDateTime = g.responseDateTime,
unitPrice = g.unitPrice,
totalPrice = g.totalPrice,
coupons = g.coupons.Select(c => new GameCouponBankVM
{
Pin = c.Pin,
Serial = c.Serial,
expiryDate = c.expiryDate
}).ToList()
})).ToListAsync();
if (gameBankResult.Count() != 0)
{
foreach (var item in gameBankResult)
{
item.referenceId = initiate.referenceId;
context.Entry(item).State = System.Data.Entity.EntityState.Modified;
}
await context.SaveChangesAsync();
return Ok(gameBankResult);
}
How can I update referenceId on my GameBank model/table?
In this scenario, your data won't be updated because your query is returning a List of GameBankVM and not a List of GameBank, now technically speaking, you are breaking SRP, you should either update your data or query your data not both in the same method, you may want to refactor your method like this :
1.- Create a private method for data update, in this case, you query directly GameBank iterate thru list entries, make your changes and save them to the database, this same method can return List of GameBank to avoid another database roundtrip.
2.- In the controller after you call your new method, you can run the transformation query to convert List of GameBank to List of GameBankVM and return it to the view.
There are many other ways to do this, I'm just recommending this as a less impact way to make your controller work. But if you are willing to make things better, you can create a business layer where you resolve all your business rules, or you can use patterns like CQS or CQRS.

How to use distinct with aggregate method for mongodb

I have some conditions and a level to check while fetching records from collection using MongoDB.
For this I am using below
def cursorOutput = dataSetCollection.find(whereObject,criteriaObject)
Which is working fine. but I want to use distinct with combination to above query.
def distinctMIdList = dataSetCollection.distinct(hierarchyField,whereObject)
Above is the query for distinct. How to combine two query.
I tried below which is not working
def cursorOutput = dataSetCollection.find(whereObject,criteriaObject).distinct("manager id")
whereObject is a condition to fetch results and criteriaObject is fields to fetch.
Distinct query is giving me result with only Manager id field but I am looking for other field also(use of criteriaObject).
Finally how to combine above two query. I searched for pipeline where $distinct is not available.
Thank you.
Map function:
var mapFunction = function() {
if(/*your criteria*/) {
emit("manager_id", this.manager_id);
}
};
Reduce Function:
var reduceFunction = function(managerFiled,values){
return Array.unique(values);
}

CouchDB Map/Reduce view query from Ektorp

I'm trying to execute a query from java against a Map/Reduce view I have created on the CouchDB.
My map function looks like the following:
function(doc) {
if(doc.type == 'SPECIFIC_DOC_TYPE_NAME' && doc.userID){
for(var g in doc.groupList){
emit([doc.userID,doc.groupList[g].name],1);
}
}
}
and Reduce function:
function (key, values, rereduce) {
return sum(values);
}
The view seems to be working when executed from the Futon interface (without keys specified though).
What I'm trying to do is to count number of some doc types belonging to a single group. I want to query that view using 'userID' and name of the group as a keys.
I'm using Ektorp library for managing CouchDB data, if I execute this query without keys it returns the scalar value, otherwise it just prints an error saying that for reduce query group=true must be specified.
I have tried the following:
ViewQuery query = createQuery("some_doc_name");
List<String> keys = new ArrayList<String>();
keys.add(grupaName);
keys.add(uzytkownikID);
query.group(true);
query.groupLevel(2);
query.dbPath(db.path());
query.designDocId(stdDesignDocumentId);
query.keys(keys);
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
above example works without 'keys' specified.
I have other queries working with ComplexKey like eg:
ComplexKey key = ComplexKey.of(userID);
return queryView("list_by_userID",key);
but this returns only a list of type T (List) - using CouchDbRepositorySupport of course - and cannot be used with reduce type queries (from what I know).
Is there any way to execute the query with reduce function specified and a complex key with 2 or more values using Ektorp library? Any examples highly appreciated.
Ok, I've found the solution using trial and error approach:
public int getNumberOfDocsAssigned(String userID, String groupName) {
ViewQuery query = createQuery("list_by_userID")
.group(true)
.dbPath(db.path())
.designDocId(stdDesignDocumentId)
.key(new String[]{userID,groupName});
ViewResult r = db.queryView(query);
return r.getRows().get(0).getValueAsInt();
}
So, the point is to send the complex key (not keys) actually as a single (but complex) key containing the String array, for some reason method '.keys(...)' didn't work for me (it takes a Collection as an argument). (for explanation on difference between .key() and .keys() see Hendy's answer)
This method counts all documents assigned to the specific user (specified by 'userID') and specific group (specified by 'groupName').
Hope that helps anybody executing map/reduce queries for retrieving scalar values from CouchDB using Ektorp query.
Addition to Kris's answer:
Note that ViewQuery.keys() is used when you want to query for documents matching a set of keys, not for finding document(s) with a complex key.
Like Kris's answer, the following samples will get document(s) matching the specified key (not "keys")
viewQuery.key("hello"); // simple key
viewQuery.key(documentSlug); // simple key
viewQuery.key(new String[] { userID, groupName }); // complex key, using array
viewQuery.key(ComplexKey.of(userID, groupName)); // complex key, using ComplexKey
The following samples, on the other hand, will get document(s) matching the specified keys, where each key may be either a simple key or a complex key:
// simple key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of("hello"));
viewQuery.keys(ImmutableSet.of(documentSlug1));
// simple keys
viewQuery.keys(ImmutableSet.of("hello", "world"));
viewQuery.keys(ImmutableSet.of(documentSlug1, documentSlug2));
// complex key: in essence, same as using .key()
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 } ));
// complex keys
viewQuery.keys(ImmutableSet.of(
new String[] { "hello", "world" },
new String[] { "Mary", "Jane" } ));
viewQuery.keys(ImmutableSet.of(
new String[] { userID1, groupName1 },
new String[] { userID2, groupName2 } ));
// a simple key and a complex key. while technically possible,
// I don't think anybody actually does this
viewQuery.keys(ImmutableSet.of(
"hello",
new String[] { "Mary", "Jane" } ));
Note: ImmutableSet.of() is from guava library.
new Object[] { ... } seems to have same behavior as ComplexKey.of( ... )
Also, there are startKey() and endKey() for querying using partial key.
To send an empty object {}, use ComplexKey.emptyObject(). (only useful for partial key querying)

NumericRangeQuery in NHibernate.Search

I am creating a search, where the user can both choose an interval and search on a term in the same go.
This is however giving me trouble, since I have up until have only used the usual text query.
I am wondering how I am to go about using both a NumericRangeQuery and a regular term query. Usually I would use a query below:
var parser = new MultiFieldQueryParser(
new[] { "FromPrice", "ToPrice", "Description"}, new SimpleAnalyzer());
Query query = parser.Parse(searchQuery.ToString());
IFullTextSession session = Search.CreateFullTextSession(this.Session);
IQuery fullTextQuery = session.CreateFullTextQuery(query, new[] { typeof(MyObject) });
IList<MyObject> results = fullTextQuery.List<MyObject>();
But if I was to e.g. search the range FromPrice <-> ToPrice and also the description, how should I do this, since session.CreateFullTextQuery only takes one Query object?
you can create a single query that is a BooleanQuery combining all the conditions you want to be met.
For the ranges, heres a link to the synthax using the QueryParser:
http://lucene.apache.org/core/old_versioned_docs/versions/2_9_2/queryparsersyntax.html#Range Searches