NHibernate: how to use ExpandoResultTransformer with Session.QueryOver - nhibernate

I have created a ExpandoResultTransformer, that would be used for converting query results to dto to be used in UI. It looks like this:
public class ExpandoResultTransformer : IResultTransformer
{
public object TransformTuple(object[] tuple, string[] aliases)
{
dynamic toReturn = new ExpandoObject();
for (int i = 0; i < aliases.Length; i++)
{
((IDictionary<string, object>)toReturn)[aliases[i]] = tuple[i];
}
return toReturn;
}
public IList TransformList(IList collection)
{
return collection;
}
}
When I use it against a createSQLQuery it works perfectly
var contacts = _session.CreateSQLQuery("exec up_ClientContactsView #ClientId=:clientId")
.SetParameter("clientId", request.ClientId)
.SetResultTransformer(new ExpandoResultTransformer())
.List<dynamic>();
However, when I tried using it against QueryOver, I run into trouble. There are no aliases sent in. So I tried specifying them like this
var periodTables = _session.QueryOver<PeriodTable>()
.Where(x => x.ClientPolicy.Id == request.ClientPolicyId)
.SelectList(list => list
.Select(i =>i.Id).WithAlias(()=>info.PeriodTableId) !! does not work as dynamic cannot be used in expression error
.Select(i => i.Id).WithAlias(()=>"PeriodTableId" !!! does not work either as it cannot find member error
.TransformUsing(new ExpandoResultTransformer())
.List<dynamic>();
Any ideas how to pass in aliases?

You can use an anonymous type instance to act as a template object:
var template = new { PeriodTableId = 0 };
var periodTables = _session.QueryOver<PeriodTable>()
.Where(x => x.ClientPolicy.Id == request.ClientPolicyId)
.SelectList(list => list
.Select(i =>i.Id).WithAlias(()=>template.PeriodTableId)
)
.TransformUsing(new ExpandoResultTransformer())
.List<dynamic>();

Related

Get data from database with where clause using API

I have a table named SerialNumbers containing some columns in it.
I want to get the data with SNum based on scanned value which has been listed in an Array.
Below is my code:
public class SNController : ApiController
{
[HttpGet]
public HttpResponseMessage AllSN()
{
using (SNDBContext dbContext = new SNDBContext())
{
string[] SNum = { "01070A2", "01070A3", "01070A4" };
var SerialNum = dbContext.SNumbers.Where(x => x.SN == "01070A2")
.Select(p => new { p.Name, p.Status})
.ToList();
return Request.CreateResponse(HttpStatusCode.OK, SerialNum );
}
}
When I try to hardcoded this part var SerialNum = dbContext.SNumbers.Where(x => x.SN == "01070A2"), its working.
How can I solve this issue?
Use Contains method in Where clause.
var SerialNum = dbContext.SNumbers.Where(x => SNum.Contains(x.SN))
.Select(p => new { p.Name, p.Status})
.ToList();

RavenDB - Adding Index breaks unrelated queries

When I add the index below to my raven database a simple query like
return Session.Query<R>().FirstOrDefault(x => x.RId == Id);
Always returns null. Only after forcing Raven to remove my custom index does desired functionality return. Why is this?
The Index with side effects:
public class RByLatestCommentIndex : AbstractIndexCreationTask<R>
{
public RByLatestCommentIndex()
{
SetMap();
}
void SetMap()
{
Map = r => r.Select(x => new
{
Id = x.Id,
TimeStamp = x.Comments.Count() > 0 ? x.Comments.Max(u => u.Created)
: x.Created
}).OrderByDescending(y => y.TimeStamp).Select(r => new { Id = r.Id });
}
}
public class RIdTransformer : AbstractTransformerCreationTask<R>
{
public RIdTransformer()
{
TransformResults = ids => ids.Select(x => LoadDocument<R>(x.Id));
}
}
EDIT:
In response to Ayende Rahien's comment:
There's a query in the DB which would otherwise be used (Auto/R/ByRID) but the index used looks like this, puzzling enough:
from doc in docs.Rs select new { Images_Count__ = doc.Images["Count()"], RId = doc.RId }
What explains this behaviour? And, will I have to add a static index to be able to query R by RId ?

Select or SelectList: I Want to include the entire entity

I am querying a list of objects, and then correlating them with a subquery.
I want to return the results of the subquery, as well as the root entity. But
I can't figure out how to actually return the root entity, I can only return individual properties of it.
Specifically, this works:
this.Session.QueryOver<MediaFile>(() => mediaFile)
.SelectList(list => list.Select(mf => mf.Id));
But this does not:
this.Session.QueryOver<MediaFile>(() => mediaFile)
.SelectList(list => list.Select(mf => mf));
I get the following error:
Could not resolve property : of MediaFile
Does anyone know how I can include the entity as a property in the list?
Here's my complete example:
// My target class
private class MediaFileAndCount
{
// I can successfully populate these fields.
public long MediaFileId { get; set; }
public int DistinctPlaylistCount { get;set; }
// But I want to populate this field!
public MediaFile MediaFile { get; set; }
}
private void TrySingleQuery()
{
MediaFile mediaFile = null;
PlaylistEntry playlistEntry = null;
MediaFileAndCount mfc = null;
var subQuery = QueryOver.Of<PlaylistEntry>(() => playlistEntry)
.Where(() => playlistEntry.MediaFile.Id == mediaFile.Id)
.Select(Projections.CountDistinct<PlaylistEntry>(p => p.Playlist));
var query = this.Session.QueryOver<MediaFile>(() => mediaFile)
.SelectList(list => list
.Select(mf => mf.Id).WithAlias(() => mfc.MediaFileId)
.Select(Projections.SubQuery(subQuery)).WithAlias(() => mfc.DistinctPlaylistCount)
// .Select(mf => mf).WithAlias(() => mfc.MediaFile) // This line fails
)
.TransformUsing(Transformers.AliasToBean<MediaFileAndCount>());
var results = query.List<MediaFileAndCount>();
}
another way to query it
var allMediaFiles = session.QueryOver<MediaFile>().Where(...).ToFuture(); // just get the MediaFiles into sessionCache
var results = session.QueryOver<PlaylistEntry>()
.Where(p => p.MediaFile...)
.SelectList(list => list
.GroupBy(p => p.MediaFile.Id)
.CountDistinct(p => p.Playlist))
.ToFuture<object[]>()
.Select(a => new MediaFileAndCount
{
MediaFile = session.Get<MediaFile>((long)a[0]),
DistinctPlaylistCount = (int)a[1]
})
.ToList();
foreach (var mediaFile in allMediaFiles.Except(results.Select(r => r.MediaFile)))
{
results.Add(new MediaFileAndCount { MediaFile = mediaFile });
}

RavenDB sum of a count

I'm trying to do a sum of a count of a child collection in a Raven query. It is returning a count of 0. If I use the same LINQ on the object directly, then it works with a count of 2.
Is this query possible with auto-indexing on Raven? If I need to create a map-reduce index, can someone help me with that?
[TestMethod]
public void CalculateUserClickCount()
{
var db = new EmbeddableDocumentStore { RunInMemory = true };
db.Initialize();
using (var session = db.OpenSession())
{
var user = new User();
var product = new Product();
product.Clicks.Add(new Click());
product.Clicks.Add(new Click());
user.Storefront.EndoProducts.Add(product);
session.Store(user);
session.SaveChanges();
var users = session.Query<User>()
.Customize(t => t.WaitForNonStaleResults())
.Select(t => new
{
StoreFrontId = t.Storefront.StorefrontID,
itemCount = t.Storefront.EndoProducts.Count,
updateDate = t.Storefront.LastUpdateDate,
clickCount = t.Storefront.EndoProducts.Sum(r => r.Clicks.Count), // this is improperly set to 0
TotalAffiliateRevenue = t.Storefront.SaleReports.Sum(r => r.TotalAffiliateEarnings) // this works
})
.ToList();
int clickCount = user.Storefront.EndoProducts.Sum(t => t.Clicks.Count); // this is properly set to 2
Assert.AreEqual(2, users[0].clickCount);
}
}
You don't need a map/reduce for this, because you are only operating on a single document at any time.
What you do need it s transform results, most probably, to do this.

passing object with collection from domain to modelDTO with nhibernate

above is code which I use to manipulate with data from my domain to dto model, which I use for wcf serialization. My question is how to pass object mother with collection of childrens into MotherDTO. With current code situation I pass only data without collection children. Do I need to use session in line and to add session MotherDTO dto = new MotherDTO(data, session); and to use that session to retreive collection of childrens in dto. If so, how ? Please help.
Regards,
public MotherDTO GetMotherData()
{
using (ISession session = instance.OpenSession())
{
using (ITransaction tx = session.BeginTransaction())
{
Mother data = session.Query<Mother>()
.Fetch(x => x.Childrens)
.FirstOrDefault();
tx.Commit();
MotherDTO dto = new MotherDTO(data);
return dto;
}
}
}
MotherDTO.cs
public MotherDTO(Mother x)
{
Name = x.Name;
List<Children>Childrens= new List<Children>();
foreach (Children obj in x.Childrens)
{
States.Add(obj);
}
}
Mother.cs
public virtual string Name
{
get { return _Name; }
set
{
_Name = value;
}
}
public virtual Iesi.Collections.Generic.ISet<Children> Childrens
{
get
{
return _Childrens;
}
set
{
if (_Childrens == value)
return;
_Childrens = value;
}
}
Since you're already (eager) loading your Children collection you can use Automapper to populate your DTOs.
If you want to know how to configure Automapper to work with nested collection you can read here:
Mapper.CreateMap<Order, OrderDto>()
.ForMember(dest => dest.OrderLineDtos, opt => opt.MapFrom(src => src.OrderLines));
Mapper.CreateMap<OrderLine, OrderLineDto>()
.ForMember(dest => dest.ParentOrderDto, opt => opt.MapFrom(src => src.ParentOrder));
Mapper.AssertConfigurationIsValid();