Can't believe I've found no answer to this but how can you do a query like
SELECT LTRIM(RTRIM("ColumnName")) FROM ....
in NHibernate
thanks
Having an example of Bank as POCO:
public class Bank
{
public virtual int ID { get; set; }
public virtual string City { get; set; }
public virtual string Street { get; set; }
}
There is a syntax for the LTRIM(RTRIM...
Bank bank = null;
var session = ...;
var query = session.QueryOver<BankAddress>()
.SelectList(l => l
// properties ID, City
.Select(c => c.ID).WithAlias(() => bank.ID)
.Select(c => c.City).WithAlias(() => bank.City)
// projection Street
.Select(Projections.SqlProjection(
" LTRIM(RTRIM({alias}.Street)) as Street" // applying LTRIM(RTRIM
, new string[] { "Street" }
, new IType[] { NHibernate.NHibernateUtil.String }
))
.TransformUsing(Transformers.AliasToBean<Bank>())
;
var list = query.List<Bank>();
Related
Query Code:
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = query.Statistics(out stats)
.Skip(0)
.Take(5)
.AsProjection<Org>().ToList();
public static IRavenQueryable<TResult> IndexQuery<TResult, TIndex>(this IDocumentSession session)
where TIndex : AbstractIndexCreationTask, new()
{
return session.Query<TResult, TIndex>();
}
App_OrgSearch is the index I defined as below:
public class App_OrgSearch : AbstractIndexCreationTask<Org, App_OrgSearch.IndexResult>
{
public class IndexResult
{
public string Id { get; set; }
public string BusinessName { get; set; }
public string ShortName { get; set; }
public IList<string> Names { get; set; }
public List<string> PhoneNumbers { get; set; }
public List<OrganizationUnitPhone> OrganizationUnitPhones { get; set; }
}
public App_OrganizationUnitSearch()
{
Map = docs => from doc in docs
select new
{
Id = doc.Id,
Names = new List<string>
{
doc.BusinessName,
doc.ShortName,
},
BusinessName = doc.BusinessName,
ShortName = doc.ShortName,
PhoneNumbers = doc.OrganizationUnitPhones.Where(x => x != null && x.Phone != null).Select(x => x.Phone.Number),
};
Indexes.Add(x => x.Names, FieldIndexing.Analyzed);
}
}
I have 27 records in database. I want to take 5, but after query, all 27 records are returned. Why does Take function not work?
Your sample code seems wrong.
var query = session.IndexQuery<App_OrgSearch.IndexResult, App_OrgSearch>();
var organizationUnitResults = organizationUnitsQuery.Statistics(out stats)
What is organizationUnitsQuery ? You have the query as query, but there is no IndexQuery method on the session
Assuming the following class:
public class Thing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
}
and the following result class:
public class ProjectedThing
{
public string Id { get; set; }
public string Title{ get; set; }
public string KeyId { get; set; }
public CultureInfo Culture { get; set; }
public IEnumerable<Thing> Things { get; set; }
}
How can I build an index that holds the result class?
The closest I've come is with the following index definition:
public class ProjectedThings : AbstractIndexCreationTask<Thing,ProjectedThing>
{
public ProjectedThings()
{
Map = docs => from doc in docs
select new
{
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
Things = new[] {
new Thing{
Id = doc.Id,
Title = doc.Title,
KeyId = doc.KeyId,
Culture = doc.Culture,
TitlePluralized = doc.TitlePluralized
}
}
};
Reduce = results => from r in results
group r by r.KeyId into g
select new
{
Title = g.FirstOrDefault(x => x.Id == x.KeyId).Title,
KeyId = g.Key,
Culture = g.FirstOrDefault(x => x.Id == x.KeyId).Culture,
Things = from thing in g.SelectMany(x => x.Things).Where(x => x.Id != x.KeyId)
select new
{
Id = thing.Id,
Title = thing.Title,
KeyId = thing.Key,
Culture = thing.Culture
}
};
}
}
That's almost doing the trick, but I can't collect the Title, KeyId, and Culture in the reduction. Only the Things property is being populated.
Look at your code:
g.FirstOrDefault(x => x.Id == x.KeyId)
I don't understand this, but this is likely to be always false.
You probably want:
g.FirstOrDefault().Title,
I'm trying to define an index in RavenDb that uses the output of another index as it's input but I can't get it to work.
I have the following entities & indexes defined.
SquadIndex produces the result I expect it to do but SquadSizeIndex doesn't even seem to execute.
Have I done something wrong or is this not supported?
class Country
{
public string Id { get; private set; }
public string Name { get; set; }
}
class Player
{
public string Id { get; private set; }
public string Name { get; set; }
public string CountryId { get; set; }
}
class Reference
{
public string Id { get; set; }
public string Name { get; set; }
}
class SquadIndex : AbstractIndexCreationTask<Player, SquadIndex.Result>
{
public SquadIndex()
{
Map = players => from player in players
let country = LoadDocument<Country>(player.CountryId)
select new Result
{
Country = new Reference
{
Id = country.Id,
Name = country.Name
},
Players = new[]
{
new Reference
{
Id = player.Id,
Name = player.Name
}
}
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
Players = g.SelectMany(x => x.Players)
};
}
internal class Result
{
public Reference Country { get; set; }
public IEnumerable<Reference> Players { get; set; }
}
}
class SquadSizeIndex : AbstractIndexCreationTask<SquadIndex.Result, SquadSizeIndex.Result>
{
public SquadSizeIndex()
{
Map = squads => from squad in squads
select new Result
{
Country = squad.Country,
PlayerCount = squad.Players.Count()
};
Reduce = results => from result in results
group result by result.Country
into g
select new Result
{
Country = g.Key,
PlayerCount = g.Sum(x => x.PlayerCount)
};
}
internal class Result
{
public Reference Country { get; set; }
public int PlayerCount { get; set; }
}
}
No, you can't. The output of indexes are not documents to be indexed.
You can use the scripted index results to chain indexes, but that isn't trivial.
Either I'm having a mental block, or its not that straightforward.
I have 2 classes, something like that:
public class House
{
public string Id { get; set; }
public string City { get; set; }
public string HouseNumber { get; set; }
}
public class Person
{
public string Id { get; set; }
public string HouseId { get; set; }
public string Name { get; set; }
}
Now I want a list of all people living in a given city, in a flattened model ({City, HouseNumber, PersonName}).
I can't figure out a way on how to map that.. If I had a City in a Person class that would be easy, but I don't, and it doesn't make sense there, imo.
Help ?
Edit:
I came up with this index, which actually works with in-memory list, but Raven returns nothing :(
public class PeopleLocations : AbstractMultiMapIndexCreationTask<PeopleLocations.EntryLocation>
{
public class PeopleLocation
{
public string PersonId { get; set; }
public string HouseId { get; set; }
public string City { get; set; }
}
public PeopleLocations()
{
this.AddMap<House>(venues => venues.Select(x => new
{
x.City,
HouseId = x.Id,
PersonId = (string)null
}));
this.AddMap<Person>(people => people.Select(x => new
{
City = (string)null,
HouseId = x.HouseId,
PersonId = x.Id
}));
this.Reduce = results => results.GroupBy(x => x.HouseId)
.Select(x => new
{
HouseId = x.Key,
People = x.Select(e => e.PersonId),
City = x.FirstOrDefault(y => y.City != null).City,
})
.SelectMany(x =>
x.People.Select(person => new PeopleLocation
{
PersonId = person,
HouseId = x.HouseId,
City = x.City,
})
)
.Select(x => new { PersonId = x.PersonId, x.City, x.HouseId });
}
}
You can do this with a MultiMap Index - but there's a great new feature in RavenDB 2.0 called Indexing Related Documents that is much easier.
Map = people => from person in people
let house = LoadDocument<House>(person.HouseId)
select new
{
house.City,
house.HouseNumber,
PersonName = person.Name,
}
I'm attempting to apply Ayende's order search from here to an existing index.
The current index looks like this:
public class HomeBlurb_IncludeTotalCosts_Search2 : AbstractIndexCreationTask<MPDocument, HomeBlurb_IncludeTotalCosts_Search2.ReduceResult>
{
public class ReduceResult
{
public string Name { get; set; }
public string Constituency { get; set; }
public decimal? AmountPaid { get; set; }
}
public HomeBlurb_IncludeTotalCosts_Search2()
{
Map = mps => from mp in mps
from exp in mp.Expenses
select new
{
mp.Name,
mp.Constituency,
exp.AmountPaid
};
Reduce = results => from result in results
group result by new { result.Name, result.Constituency } into g
select new
{
Name = g.Key.Name,
Constituency = g.Key.Constituency,
AmountPaid = g.Sum(x => x.AmountPaid)
};
Index(x => x.Name, FieldIndexing.Analyzed);
Index(x => x.Constituency, FieldIndexing.Analyzed);
}
}
This index works fine. However when I try to change the Map to:
from mp in mps
from exp in mp.Expenses
select new
{
Query = new object[]{mp.Name,mp.Constituency},
mp.Name,
mp.Constituency,
exp.AmountPaid
};
and the reduce to
from result in results
group result by new { result.Name, result.Constituency } into g
select new
{
Query = "",
Name = g.Key.Name,
Constituency = g.Key.Constituency,
AmountPaid = g.Sum(x => x.AmountPaid)
};
I then get no results when querying on the Query property. If I remove the reduce the index returns data, but it always returns the full MPDocument, which is much more that I was to materialise. Is there a way to use the technique described in the original post that also utilises a reduce?
You can use this in your reduce function:
Query = g.Select(x => x.Query).Where(x => x != null).FirstOrDefault()
In order to query on that field, you need to have a seperate query model and a result model. Here is a full example using your code:
public class MultiTermFieldInMapReduce
{
public class MPDocument
{
public List<Epense> Expenses { get; set; }
public string Name { get; set; }
public string Constituency { get; set; }
public class Epense
{
public decimal? AmountPaid { get; set; }
}
}
public class HomeBlurb_IncludeTotalCosts_Search2 : AbstractIndexCreationTask<MPDocument, HomeBlurb_IncludeTotalCosts_Search2.ReduceResult>
{
public class ReduceResult
{
public string Name { get; set; }
public string Constituency { get; set; }
public decimal? AmountPaid { get; set; }
public object[] Query { get; set; }
}
public class SearchModel
{
public string Name { get; set; }
public string Constituency { get; set; }
public decimal? AmountPaid { get; set; }
public string Query { get; set; }
}
public HomeBlurb_IncludeTotalCosts_Search2()
{
Map = mps => from mp in mps
from exp in mp.Expenses
select new
{
mp.Name,
mp.Constituency,
exp.AmountPaid,
Query = new object[]
{
mp.Name,
mp.Constituency
}
};
Reduce = results => from result in results
group result by new { result.Name, result.Constituency } into g
select new
{
Name = g.Key.Name,
Constituency = g.Key.Constituency,
AmountPaid = g.Sum(x => x.AmountPaid),
Query = g.Select(x => x.Query).Where(x => x != null).FirstOrDefault()
};
Index(x => x.Name, FieldIndexing.Analyzed);
Index(x => x.Constituency, FieldIndexing.Analyzed);
}
}
[Fact]
public void Query_returns_results()
{
using (var store = new EmbeddableDocumentStore { RunInMemory = true }.Initialize())
{
using (var session = store.OpenSession())
{
session.Store(new MapReduceError.MPDocument
{
Name = "test1",
Expenses = new List<MapReduceError.MPDocument.Epense>
{
new MapReduceError.MPDocument.Epense {AmountPaid = 5.5m},
new MapReduceError.MPDocument.Epense {AmountPaid = 5.5m},
new MapReduceError.MPDocument.Epense {AmountPaid = 5.5m},
new MapReduceError.MPDocument.Epense {AmountPaid = 5.5m}
}
});
session.Store(new MapReduceError.MPDocument
{
Name = "test2",
Expenses = new List<MapReduceError.MPDocument.Epense>
{
new MapReduceError.MPDocument.Epense {AmountPaid = 10},
new MapReduceError.MPDocument.Epense {AmountPaid = 10},
new MapReduceError.MPDocument.Epense {AmountPaid = 10},
new MapReduceError.MPDocument.Epense {AmountPaid = 10}
}
});
session.SaveChanges();
}
new HomeBlurb_IncludeTotalCosts_Search2().Execute(store);
using (var session = store.OpenSession())
{
var results =
session.Query
<HomeBlurb_IncludeTotalCosts_Search2.SearchModel, HomeBlurb_IncludeTotalCosts_Search2>()
.Customize(x => x.WaitForNonStaleResultsAsOfLastWrite())
.Where(x => x.Query == "test1")
.As<HomeBlurb_IncludeTotalCosts_Search2.ReduceResult>()
.ToList();
Assert.Equal(1, results.Count);
Assert.Equal(22, results.First().AmountPaid);
}
}
}
}
I don't think you need a Map/Reduce index to do this, you seem to only be reducing on MPDocument Name and Constituency, which I guess are unique to each MP.
I think that you want to use TransformResults, so that you can change the shape of the output instead, something like so:
TransformResults =
(database, mps) => from mp in mps
select new
{
mp.Name,
mp.???
< JUST THE BITS YOU WANT RETURNED >
};
Then you query like so:
session.Query<mp>("index name")
.Where(..)
.As<MPQueryResult>()
.ToList()