Thursday, June 6, 2013

ViewPaper and Fragment: How to update data of active fragment item

For example, I use ViewPaper to flip left and right through pages of data. But when a fragment item has been active, I need to update some related data and state.

So, I need to implement the fragment adapter that extends from FragmentStatePagerAdapter and override methods to keep reference from position to fragment item, in this case, we can use HashMap but in Android SDK recommend, I used SparseArray to keep this reference. On the activity or fragment parent, implement listener OnPageChangeListener for PageIndicator to detect the position of fragment item has been activated and update related data's state.

The adapter can implement as following:

public static class MyAdapter extends FragmentStatePagerAdapter {
    private SparseArray<TestFragment> mPageReferenceMap 
                              = new SparseArray<TestFragment>();
    ...

    @Override 
    public Object instantiateItem(ViewGroup viewGroup, int position) {
        Object obj = super.instantiateItem(viewGroup, position);

        //Add the reference when fragment has been create or restore
        if (obj instanceof TestFragment) {
                TestFragment f= (TestFragment)obj;
                mPageReferenceMap.put(position, f);
        }

        return obj;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        //Remove the reference when destroy it
        mPageReferenceMap.remove(position);

        super.destroyItem(container, position, object);
    }

    public TestFragment getFragment(int key) {

        return mPageReferenceMap.get(key);
    }
    ...
}

Hope this help.

Sunday, June 3, 2012

Create select sub-query on NHibernate

On this sample, I will show you how to create select sub-query on NHibernate by using DetachedCriteria and Projections.

For example, I have a model with following structure:

public partial class Auction
{
    public virtual long AuctionID { get; set; }
    public virtual IList<MaxBid> MaxBids { get; set; }

    public virtual DateTimeOffset EndDate { get; set; }
}
public partial class Account {
  public virtual long AccountID { get; set; }
}
    
public partial class MaxBid {
        public virtual long MaxBidID { get; set; }
        public virtual Auction Auction { get; set; }
        public virtual Account BuyerAccount { get; set; }
    }
public partial class Bid {
	public virtual long BidID { get; set; }
	public virtual MaxBid MaxBid { get; set; }
    public virtual bool IsRetracted { get; set; }
}

We have to create a query to get all auction, on each auction, we have to determine the current bid price (the latest bid record) and the current buyer’s max bid price (the latest max bid record by buyer) without retraction status. We can easily create a SQL Transact query as following (on this example, buyer account id = 1):

SELECT Auction.AuctionID
	, Auction.AssetClassID
	, Auction.EndDate
	, (SELECT MAX(Bid.BidPrice) FROM MaxBid LEFT JOIN Bid ON MaxBid.MaxBidID = Bid.MaxBidID 
		WHERE MaxBid.AuctionID = Auction.AuctionID AND MaxBid.IsRetracted = 0
		) AS CurrentBid
	, (SELECT MAX(MaxBid.MaxBidPrice) FROM MaxBid 
		WHERE MaxBid.AuctionID = Auction.AuctionID 
		AND MaxBid.IsRetracted = 0 AND MaxBid.BuyerAccountID = 1
		) AS MyMaxBid  
FROM Auction

This query select all auction, each auction, we have to get maximum bib price without retraction and buyer’s maximum bid price.

We can create NHibernate query to do this as following:

var myMaxBidQuery =
    DetachedCriteria.For<MaxBid>("mb")
    .Add(Restrictions.Eq("mb.IsRetracted", false))
    .Add(Restrictions.Eq("mb.BuyerAccount.AccountID", 1L))
    .Add(Property.ForName("mb.Auction.AuctionID").EqProperty("a.AuctionID"))
    .SetProjection(Projections.Max("mb.MaxBidPrice"));

var currentBidQuery =
    DetachedCriteria.For<MaxBid>("mb")
    .CreateAlias("mb.Bids", "b", JoinType.LeftOuterJoin)
    .Add(Restrictions.Eq("mb.IsRetracted", false))
    .Add(Property.ForName("mb.Auction.AuctionID").EqProperty("a.AuctionID"))
    .SetProjection(Projections.Max("b.BidPrice"));

var query =
    DetachedCriteria.For<Auction>("a")
        .SetProjection(Projections.ProjectionList()
        .Add(Projections.Property("a.AuctionID"))
        .Add(Projections.Property("a.AssetClass.AssetClassID"))
        .Add(Projections.Property("EndDate"))
        .Add(Projections.SubQuery(currentBidQuery))
        .Add(Projections.SubQuery(myMaxBidQuery)))
        .SetResultTransformer(Transformers.AliasToBean<DataResult>());

var results = query.GetExecutableCriteria(session).List<DataResult>();

In this case, I created two DetachedCriteria objects to perform sub-queries, each sub-query has a Property.ForName to put the relation to main query by equal property (EqProperty). And on the main query, they will be add into main query by using Projections.SubQuery. And the result, I used Transformers to transform the result to customized bean based on the structure of query, we can create transformer result class as following code snippet:

public class DataResult
{
    public long AuctionID { get; set; }
    public int AssetClassID { get; set; }
    public DateTimeOffset EndDate { get; set; }
    public decimal MaxBidPrice { get; set; }
    public decimal BidPrice { get; set; }
}

Hope that by this sample, I can help you to create more complex queries using DetachedCriteria, Projections and Transformer on NHibernate and of course, we can translate it to Hibernate on Java.

Thursday, October 20, 2011

LINQ to Entities: PredicateBuilder and Dynamic Linq

When you want to build dynamic filter for a query on LINQ to SQL or LINQ to Entities (Entity Framework, NHibernate, ..), you can use a famous Albahari's PredicateBuilder. But sometime, it may be doesn't work perfect with LINQ to Entities. To solve this problem, Pete Montgomery introduced a universal PredicateBuilder that combined the original version of Albahari's PredicateBuilder and LINQ to Entities: Combining Predicates.