How to map two variables from SQL Query - MyBatis - sql

So, I have this select query below, which joins two tables and retrieves a String:
<select id =“getAppVerByConfId” parameterType=“java.lang.String” resultType=“java.lang.String”>
SELECT t.app_ver
FROM
application a
JOIN transaction t on t.txn_id = a.txn_id
WHERE
a.confirmation_id = #{0}
</select>
and then I used that as a template to write a 2nd query, which is nearly identical, but just retrieves a different parameter from the table.
<select id =“getStepNameByConfId” parameterType=“java.lang.String” resultType=“java.lang.String”>
SELECT t.step_name
FROM
application a
JOIN transaction t on t.txn_id = a.txn_id
WHERE
a.confirmation_id = #{0}
Both of these work fine on their own, and they're used at the same point in the program. But there's got to be a better way than this surely? I should be able to make the query once, and then map the results to what I want, correct? Should I make a resultset, and then be able to pull them out? Maybe as a HashMap and I can retrieve the values by keys? Is this a situation where I can USE the AS operator? i.e. "SELECT t.app_ver AS appVersion"? My thinking is that's for passing variables into the query, though, and not for getting them out?
If there's any thoughts on this I would love to hear them. I'm basically trying to combine these into one query, and I need to be able to retrieve the right value and not assign app_ver to step_name or vice versa.
Cheers

As you say it's not a bad idea use alias (t.app_ver as appVersion) in your select but it is just the name of the column which will be mapped. So in the case you use alias as next t.app_ver as appVersion, t.step_name as stepName your column names will be appVersion and stepName.
Then, to map your result you have multiple choices the idea to map it in a map structure is not a bad idea and it's easy, you just need to put your result type as hashmap, it will be something like that (and it's not need any Resultmap):
Hashmap
(Example in offical page)
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
The column will be the key and the row values the value in the map.
keyed by column names mapped to row values
So to get your values you will need to use the column name as key in the map:
String appVersionValue = map.get("appVersion");
Resultmap
Other way it to create a class with the properties you need to map and then create your resultmap.
A resultmap is defined as next:
resultMap – The most complicated and powerful element that describes
how to load your objects from the database result sets.
Your class would be like:
public class Application{
private String appVersion;
private String stepName;
//.... getters and setters
}
And your result map would map the column name with the class properties specifying the type with the class created for this (In this case is Application):
<resultMap id="applicationResultMap" type="Application">
<result property="appVersion" column="appVersion"/>
<result property="stepName" column="stepName"/>
</resultMap>
(Be careful, because in this example the columns and properties are called equal, there are cases where the column is called app_version and the property appVersion for example so there would be <result property="appVersion" column="app_version"/>
Finally in your select you specify to use this resultmap:
<select id="selectMethodName" resultMap="applicationResultMap">
select t.app_ver as appVersion, t.step_name as stepName
from your_table
</select>

Related

ADO.NET - Accessing Each DataView in DataViewManager

Looks like a silly question, but I can't find a way to access the DataViews in my DataViewManager.
I can see it in the DataViewManager Visualizer window, so there must be a way.
What am I doing wrong?
dvm = New DataViewManager(MyDS) ''-- MyDS is a strongly typed dataset
dvm.CreateDataView(MyDS.Company)
dvm.CreateDataView(MyDS.Sites)
MsgBox(dvm.DataViewSettings.Count) ''-- shows 7, even though I added only 2.
For Each view As DataView In dvm ''-- Error!
MsgBox(view.Table.TableName)
Next
I also observed that irrespective of how many DataViews I create, data the DataViewManager Visualizer shows all DataViews in my dataset. Why?
how do I hide those rows in parent whose child data view returns 0 rows after applying RowFilter on child
I've done it like this, but it feels like a nasty hack; I've never read the source deeply enough to know if there is a better way:
Add a column to your child datatable: Name: IsShowing, Type: Int, Expression: 1, ReadOnly: True
Put the following code:
ChildBindingSource.RemoveFilter()
ParentBindingSource.RemoveFilter()
YourDataSet.ChildDataTable.IsShowingColumn.Expression = ""
YourDataSet.ChildDataTable.Expression = $"IIF([SomeColumn] Like '{SomeFilterText}',1,0)"
ChildBindingSource.Filter = "[IsShowing] > 0"
ParentBindingSource.Filter = "Sum(Child.IsShowing) > 0"
The removal and re-add triggers a re-evaluation of the expression and the filters. There is probably a way to do this without removing/re-adding but I haven't yet found it.. Expressions are normally only re-evaluated when row data changes; changing an expression doesn't seem to recalculate all the row values/trigger a refresh of the relations and BS filters
It would be great if the parent filter supported complex expressions like SUM(IIF(Child.SomeColumn = 'SomeFilter',1,0)>0 but the SUM operator expects only a column name in the parent or child. As such, the circuitous route of having a column with an Expression be the part inside the SUM is the only way i've found to leverage the built in filtering
Remember when you test that the search is case sensitive. If you want it not to be you might have to have another column of data that is the lowercase version of what you want to search and lowercase your query string

GET url with nested element inside query string

Using Postman, I am forming a GET request query to my P21 database middleware to retrieve items with a specific value in a UserDefinedField.
I am able to query things on the top level of the item data, such as ItemID and ItemDesc like so:
http://[server]:[port]/api/inventory/parts?$query=ItemDesc eq 'CONTROL VALVE'
However, the values I would like to use in my query string are nested inside the UserDefinedFeilds element. I am specifically looking for items with:
http://[server]:[port]/api/inventory/parts?$query=UserDefinedFeilds/OnEbay eq 'Y'
But this is not the correct way to form this query string. Can anyone please explain how to specify a nested element inside a query string like this? Thanks.
In this situation, using P21 API, it is unnecessary to specify the parent field 'UserDefinedFields'. The actual ID of the column I was looking for was actually 'on_ebay', so I was able to query this user defined field simply:
http://[server]:[port]/api/inventory/parts?$query=on_ebay eq 'Y'

Django ORM Cross Product

I have three models:
class Customer(models.Model):
pass
class IssueType(models.Model):
pass
class IssueTypeConfigPerCustomer(models.Model):
customer=models.ForeignKey(Customer)
issue_type=models.ForeignKey(IssueType)
class Meta:
unique_together=[('customer', 'issue_type')]
How can I find all tuples of (custmer, issue_type) where there is no IssueTypeConfigPerCustomer object?
I want to avoid a loop in Python. A solution which solves this in the DB would be preferred.
Background: for every customer and for every issue-type, there should be a config in the DB.
If you can afford to make one database trip for each issue type, try something like this untested snippet:
def lacking_configs():
for issue_type in IssueType.objects.all():
for customer in Customer.objects.filter(
issuetypeconfigpercustomer__issue_type=None
):
yield customer, issue_type
missing = list(lacking_configs())
This is probably OK unless you have a lot of issue types or if you are doing this several times per second, but you may also consider having a sensible default instead of making a config object mandatory for each combination of issue type and customer (IMHO it is a bit of a design-smell).
[update]
I updated the question: I want to avoid a loop in Python. A solution which solves this in the DB would be preferred.
In Django, every Queryset is either a list of Model instances or a dict (values querysets), so it is impossible to return the format you want (a list of tuples of Model) without some Python (and possibly multiple trips to the database).
The closest thing to a cross product would be using the "extra" method without a where parameter, but it involves raw SQL and knowing the underlying table name for the other model:
missing = Customer.objects.extra(
select={"issue_type_id": 'appname_issuetype.id'},
tables=['appname_issuetype']
)
As a result, each Customer object will have an extra attribute, "issue_type_id", containing the id of one IssueType. You can use the where parameter to filter based on NOT EXISTS (SELECT 1 FROM appname_issuetypeconfigpercustomer WHERE issuetype_id=appname_issuetype.id AND customer_id=appname_customer.id). Using the values method you can have something close to what you want - this is probably enough information to verify the rule and create the missing records. If you need other fields from IssueType just include them in the select argument.
In order to assemble a list of (Customer, IssueType) you need something like:
cross_product = [
(customer, IssueType.objects.get(pk=customer.issue_type_id))
for customer in
Customer.objects.extra(
select={"issue_type_id": 'appname_issuetype.id'},
tables=['appname_issuetype'],
where=["""
NOT EXISTS (
SELECT 1
FROM appname_issuetypeconfigpercustomer
WHERE issuetype_id=appname_issuetype.id
AND customer_id=appname_customer.id
)
"""]
)
]
Not only this requires the same number of trips to the database as the "generator" based version but IMHO it is also less portable, less readable and violates DRY. I guess you can lower the number of database queries to a couple using something like this:
missing = Customer.objects.extra(
select={"issue_type_id": 'appname_issuetype.id'},
tables=['appname_issuetype'],
where=["""
NOT EXISTS (
SELECT 1
FROM appname_issuetypeconfigpercustomer
WHERE issuetype_id=appname_issuetype.id
AND customer_id=appname_customer.id
)
"""]
)
issue_list = dict(
(issue.id, issue)
for issue in
IssueType.objects.filter(
pk__in=set(m.issue_type_id for m in missing)
)
)
cross_product = [(c, issue_list[c.issue_type_id]) for c in missing]
Bottom line: in the best case you make two queries at the cost of legibility and portability. Having sensible defaults is probably a better design compared to mandatory config for each combination of Customer and IssueType.
This is all untested, sorry if some homework was left for you.

Entity Framework Dynamic Lambda to Perform Search

I have the following entities in Entity Framwork 5 (C#):
OrderLine - Id, OrderId, ProductName, Price, Deleted
Order - Id, CustomerId, OrderNo, Date
Customer - Id, CustomerName
On the order search screen the user can enter the following search values:
ProductName, OrderNo, CustomerName
For Example they might enter:
Product Search Field: 'Car van bike'
Order Search Field: '100 101 102'
Customer Search Field: 'Joe Jack James'
This should do a OR search (ideally using linq to entities) for each entered word, this example would output the following where sql.
(ProductName like 'Car' Or ProductName like 'van' Or ProductName like 'bike') AND
(OrderNo like '100' Or OrderNo like '101' Or OrderNo like '102') AND
(CustomerName like 'Joe' Or CustomerName like 'Jack' Or CustomerName like 'James')
I want to do this using linq to entities, i am guessing this would need to be some sort of dynamic lambda builder as we don't know how many words the user might enter into each field.
How would i go about doing this, i have had a quick browse but cant see anything simple.
You can build a lambda expression using Expression Trees . What you need to do is split the value and build the expression . Then you can convert in in to a lambda expression like this,
var lambda = Expression.Lambda<Func<object>>(expression);
Here is an example
There are 2 basic approaches to Dynamic Expressions and Queries in LINQ.
3 if you count using Json as the approach to get a lambda expression. => Akash Kava post
a) String Dynamic Lambda
System.Linq.Dynamic can be found at following links
http://msdn.microsoft.com/en-US/vstudio/bb894665.aspx
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
http://www.scottgu.com/blogposts/dynquery/dynamiclinqcsharp.zip
b) Build Expression trees
More powerful but harder to master...
Build expressions trees with code found here:
http://msdn.microsoft.com/en-us/library/system.linq.expressions.aspx
an alternate approach is predicate builder but it isnt really that dynamic.
but can deal with the OR type scenario you give as example.
http://www.albahari.com/nutshell/predicatebuilder.aspx
I would recomend to go slightly different way from answers above and use EntitySQL as it is trivial to build SQL-like string with dynamic conditions.
http://msdn.microsoft.com/en-us/library/bb738683.aspx
Disclaimer: I am author of Entity REST SDK.
You can look at Entity REST SDK at http://entityrestsdk.codeplex.com
You can query using JSON syntax as shown below,
/app/entity/account/query?query={AccountID:2}&orderBy=AccountName
&fields={AccountID:'',AcccountName:''}
You can use certain extensions provided to convert JSON to lambda.
And here is details of how JSON is translated to Linq. http://entityrestsdk.codeplex.com/wikipage?title=JSON%20Query%20Language&referringTitle=Home
Current Limitations of OData v3
Additionally, this JSON based query is not same as OData, OData does not yet support correct way to search using navigation properties. OData lets you search navigation property inside a selected entity for example Customer(1)/Addresses?filter=..
But here we support both Any and Parent Property Comparison as shown below.
Example, if you want to search for List of Customers who have purchased specific item, following will be query
{ 'Orders:Any': { 'Product.ProductID:==': 2 } }
This gets translated to
Customers.Where( x=> x.Orders.Any( y=> y.Product.ProductID == 2))
There is no way to do this OData as of now.
Advantages of JSON
When you are using any JavaScript frameworks, creating query based on English syntax is little difficult, and composing query is difficult. But following method helps you in composing query easily as shown.
function query(name,phone,email){
var q = {};
if(name){
q["Name:StartsWith"] = name;
}
if(phone){
q["Phone:=="] = phone;
}
if(email){
q["Email:=="] = email;
}
return JSON.stringify(q);
}
Above method will compose query and "AND" everything if specified. Creating composable query is great advantage with JSON based query syntax.

OData $filter with items in a $expand

I have given some web services to access informations.
The first thing that i have tries to expand a node . And i have done that successfully with following code
http://www.domain.com/ODataService/WorkService.svc/CaseStudies?format=json&$expand=ServiceOfferings
Now i want to filter ServiceOfferingID that i will get when expanding ServiceOfferings .
How can use filter option against a expanded collection
http://www.domain.com/ODataService/WorkService.svc/CaseStudies?format=json&$expand=ServiceOfferings&$filter=ServiceOfferings.ServiceOfferingID eq 127
But its not working. What is right way to do the same
The query you'll need to write depends on the cardinality of the expanded collection.
Here are some examples that use the public sample OData Northwind service, provided by odata.org.
An order is always done by exactly one customer.
Find the orders made by a customer with a specific name:
http://services.odata.org/V3/Northwind/Northwind.svc/Orders?$expand=Customer&$filter=Customer/CompanyName eq 'Vins et alcools Chevalier'. This is equivalent to the answer of Dhawal.
A customer can issue many orders.
Use the quantifiers all or any to specify whether you want at least one, or all of the orders to obey your conditions.
Find customers for which one or more orders have been processed by a specific employee:
http://services.odata.org/V3/Northwind/Northwind.svc/Customers?$expand=Orders&$filter=Orders/any(o: o/EmployeeID eq 9)
Find customers that haven't ordered anything for a long time:
http://services.odata.org/V3/Northwind/Northwind.svc/Customers?$expand=Orders&$filter=Orders/all(o: o/OrderDate lt DateTime'1997-01-01')
You can call http://services.odata.org/V3/Northwind/Northwind.svc/$metadata and inspect the NavigationProperty elements, to see which relations exist.
<NavigationProperty Name="Orders"
Relationship="NorthwindModel.FK_Orders_Customers"
ToRole="Orders"
FromRole="Customers"/>
Then, look for an association with that name and you'll find the cardinality:
<Association Name="FK_Orders_Customers">
<End
Type="NorthwindModel.Customer"
Role="Customers"
Multiplicity="0..1"/>
<End
Type="NorthwindModel.Order"
Role="Orders"
Multiplicity="*"/>
...
Navigating a one-to-many relationship like this: http://services.odata.org/V3/Northwind/Northwind.svc/Customers?$expand=Orders&$filter=Orders/EmployeeID eq 9, will give you: "The parent value for a property access of a property 'EmployeeID' is not a single value. Property access can only be applied to a single value."
Navigating a many-to-one relationship with all or any, like http://services.odata.org/V3/Northwind/Northwind.svc/Orders?$expand=Customer&$filter=Customer/any(c: c/CompanyName eq 'Vins et alcools Chevalier'), will give you:
"Any/All may only be used following a collection."
By the way, all() and any() are actually the Universal quantifier, ∀() and the existential quantifier, ∃(), respectively, which you may remember from math class.
Filtering by child object's properties is supported in oData.
Here is an example:
http://services.odata.org/Northwind/Northwind.svc/Orders?$filter=Customer/Country eq 'Germany'
Might be helpful for someone
GET serviceRoot/People?$expand=Trips($filter=Name eq 'Trip in US')
In OData the Filter command only works on the top level element. For your filter to work you would need to have the following URL
http://www.example.com/ODataService/WorkService.svc/CaseStudies(x)/ServiceOfferings?format=json&$filter=ServiceOfferingID eq 127
Obviously this isn't the query you are trying to write, but behind the scenes your query is being converted to an expression tree which has a root expression based on the top level element.
If you really required to filter the data you could potentially intercept the query and write your own expression as below:
[QueryInterceptor("CaseStudies")]
public Expression<Func<CaseStudie, bool>> CaseStudieFilter()
{
<Expression here>
}
You can also accomplish this through a webget on the service. I have had to do something similar to filter by properties of properties.