RavenDB Upgrade: 2.5 to 3.5 - Cannot compile index - ravendb

I'm currently in the process of upgrading our Solution from RavenDB 2.5 to 3.5 but getting the following exception when creating indexes: Looks like it has something to do with the group by
IndexCreation.CreateIndexes(typeof(RavenGuid).Assembly, store);
Index Definition
public RecordingArtistTypeaheadIndex()
{
Map = docs => docs.Select(x => new Definition { Artist = x.ArtistDisplayName });
Reduce = results => results.SelectMany(r => r.Artist.Split('|')).GroupBy(x => x).Select(g => new Definition { Artist = g.Key });
Store(x => x.Artist, FieldStorage.Yes);
Index(x => x.Artist, FieldIndexing.Analyzed);
}
Exception message
Compilation Errors:
Line 40, Position 11: Error CS1525 - Invalid expression term 'by'
Line 40, Position 14: Error CS0745 - Expected contextual keyword 'by'
Source code
public class Index_RecordingArtistTypeaheadIndex : Raven.Database.Linq.AbstractViewGenerator
{
public Index_RecordingArtistTypeaheadIndex()
{
this.ViewText = #"from x in docs.RepertoireResources
select new {
Artist = x.ArtistDisplayName
}
from x in results.SelectMany(r => r.Artist.Split(new char[] {'|'}))
group x by x into g
select new {
Artist = g.Key
}";
this.ForEntityNames.Add("RepertoireResources");
this.AddMapDefinition(docs =>
from x in ((IEnumerable<dynamic>)docs)
where string.Equals(x["#metadata"]["Raven-Entity-Name"], "RepertoireResources", System.StringComparison.InvariantCultureIgnoreCase)
select new {
Artist = x.ArtistDisplayName,
__document_id = x.__document_id
});
this.ReduceDefinition = results =>
from x in results.SelectMany((Func<dynamic, IEnumerable<dynamic>>)(r => (IEnumerable<dynamic>)(r.Artist.Split(new char[] {
'|'
}))))
group by x into g
select new {
Artist = g.Key
};
this.GroupByExtraction = x => x;
this.AddField("Artist");
this.AddQueryParameterForMap("ArtistDisplayName");
this.AddQueryParameterForMap("__document_id");
this.AddQueryParameterForReduce("ArtistDisplayName");
this.AddQueryParameterForReduce("__document_id");
}
}
Has anyone came across this before?

Solution: I changed the reduce so that the SelectMany returns an anonymous type and then I use the .Artist property in the GroupBy
public RecordingArtistTypeaheadIndex()
{
Map = docs => docs.Select(x => new Definition
{
Artist = x.ArtistDisplayName
});
Reduce = results => results
.SelectMany(r => r.Artist.Split('|'), (x, y) => new Definition { Artist = y })
.GroupBy(x => x.Artist)
.Select(g => new Definition
{
Artist = g.Key
});
Store(x => x.Artist, FieldStorage.Yes);
Index(x => x.Artist, FieldIndexing.Analyzed);
}

Related

how to write a linq with multiple join

as am a beginner,i want to get the following set of query as linq with a detailed explanation
//my sql
select COL.title as organizationtitle,CL.[title] as
cousestitle,sum(FD.feathers) as totalfeathers,sum(FD.amount) as
totalamount
from [dbo].[FeathersDonated] FD
join [dbo].[Couses] C on FD.corpid=3 and FD.[cousesid]=C.id
join [dbo].[Couses_lang] CL on FD.[cousesid]=CL.cousesid and
CL.language='en-US'
JOIN [dbo].[Organization_lang] COL on COL.orgid=2 and COL.language='en
US'
group by FD.cousesid,CL.[title],CL.[description],COL.title
i have tried the following set of code. please do help
var featherDonated = _GoUoW.FeathersDonated.FindBy(x => x.corpid ==
param.corpid)
.GroupBy(x => x.cousesid).Select(x => new { cousesid = x.Key, amount =
x.Select(a => a.amount).DefaultIfEmpty(0).Sum(), feathers = x.Select(a =>
a.feathers).DefaultIfEmpty(0).Sum() })
.Join(_GoUoW.Couses.GetAll(), feather => feather.cousesid, couse =>
couse.id, (feather, couse) => new { feather, couse })
.Join(_GoUoW.Organization_lang.FindBy(orglang => orglang.language == "en-
US"), couses => couses.couse.orgid, orgid => (param.organizationid > 0 ?
param.organizationid : orgid.orgid), (couses, orgid) => new { couses,
orgid
})
.Join(_GoUoW.Couses_lang.FindBy(couselang => couselang.language == "en-
US"),
organization => organization.orgid.orgid, couselang => couselang.cousesid,
(organization, couselang) => new { organization, couselang })
.Select(x => new
{
x.organization.couses.feather.amount,
x.organization.couses.feather.feathers,
x.couselang.title
//x.organization.orgid.title,
}).ToList();

Search column names and tables

Is there any way to search your database for column names or tables in linqpad. Im looking for a similar feature that you can get in SSMS through red gates sql search.
You can get the table and column names from the Linq mapping. The following should dump out the table and column names.
var columns =
(from t in this.Mapping.GetTables()
from dm in t.RowType.DataMembers
where dm.DbType != null
select new
{
TableName = t.RowType.Name ,
TableSqlName = t.TableName,
dm.DbType,
ColumnName = dm.Name,
dm.IsPrimaryKey,
ColumnSqlName = dm.MappedName
}
);
columns.Dump();
So it should be straightforward to filter this query.
If you enable system tables under properties for your connection you can use a query like this (this is for MS SQL but you can probably adapt it to others)
void Main()
{
var text = "ThingToFind";
SearchColumns(text).Dump("Columns: " + text);
SearchModules(text).Dump("Modules: " + text);
}
#region
IEnumerable<dynamic> SearchColumns(string text)
{
return sys
.columns
.Join(sys.objects, o => o.object_id, i => i.object_id, (o, i) => new { Object = i, Column = o })
.Join(sys.types, o => o.Column.user_type_id, i => i.user_type_id, (o, i) => new { o.Column, o.Object, Type = i })
.Where(c => c.Object.type_desc != "INTERNAL_TABLE")
.Where(c => c.Object.type_desc != "SYSTEM_TABLE")
.OrderBy(c => c.Object.type)
.ThenBy(c => c.Object.name)
.Select(c => new { c.Object, c.Column, c.Type, Default = c.Column.default_object_id != 0 ? sys.default_constraints.Single(d => d.object_id == c.Column.default_object_id).definition : null })
.Select(c => new { Table_Type = c.Object.type_desc, Table = c.Object.name, Name = c.Column.name, Type = c.Type.name, Length = c.Column.max_length, Precision = c.Column.precision, Scale = c.Column.scale, Nullable = c.Column.is_nullable, c.Default })
.AsEnumerable()
.Where(c => c.Name.ContainsIgnoreCase(text));
}
IEnumerable<dynamic> SearchModules(string text, bool findRelatedModules = false)
{
var modules = sys
.sql_modules
.AsEnumerable()
.Join(sys.objects, o => o.object_id, i => i.object_id, (o, i) => new { i.name, definition = o.definition.Trim() })
.ToList();
var result = modules
.Where(m => m.name.ContainsIgnoreCase(text) || m.definition.ContainsIgnoreCase(text))
.ToList();
while (findRelatedModules)
{
var add = result
.SelectMany(r => r.definition.Split(" \t\n\r!##$%^&*()-=+[]{};':\",.<>/?\\|`~".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
.Distinct()
.Where(token => modules.Any(m => m.name.ToLower() == token.ToLower()))
.Where(token => !result.Any(m => m.name.ToLower() == token.ToLower()))
.ToList();
result.AddRange(add.Select(a => modules.Single(m => m.name.ToLower() == a.ToLower())));
findRelatedModules = add.Any();
}
result
.Where(m => !m.definition.ContainsIgnoreCase(m.name))
.Dump("Renamed Modules");
return result.OrderBy(r => r.name);
}
#endregion
public static class StringExtensions
{
public static bool ContainsIgnoreCase(this string source, string toCheck, bool bCaseInsensitive )
{
return source.IndexOf(toCheck, bCaseInsensitive ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal) >= 0;
}
}

Joining tables in NHibernate

I have a query below, How can recreate this one to join the tables that will return a list of SurveyProjectNormDTO using NHibernate? Any help please?
using (var session = OpenSession()){
var projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>()
.Where(x => x.NodeID == nodeId);
projectGroupIds.Fetch(x => x.ProjectGroupID).ToFuture();
var projectIds = session.Query<ProjectGroup>().Where(p => projectGroupIds.Contains(p.Id));
projectIds.Fetch(x => x.ProjectID).ToFuture();
var projectNormProjects = session.Query<SurveyProjectNorm>().Where(x => projectIds.Contains(x.SurveyProjectId));
projectNormProjects.Fetch(x => x.ShortLabels).ToFuture();
projectNormProjects.Fetch(x => x.ReportingNames).ToFuture();
projectNormProjects.Fetch(x => x.NormProject).ToFuture();
var response = new List<SurveyProjectNormDTO>();
projectNormProjects.ToList().ForEach(
p =>
{
response.Add(
new SurveyProjectNormDTO { Id = p.Id, ProjectName = p.NormProject.ProjectName, ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() });
});
return response;
I am not sure if these let commands will work fine but you can try this. It will do a single hit on the database fetching the properties. Test it and let us know if it works.
var queryResult = (from p in session.Query<SurveyProjectNorm>()
let projectGroupIds = session.Query<ReportingStructureNodeProjectGroups>().Where(x => x.NodeID == nodeId).Select(x => x.Id)
let projectIds = session.Query<ProjectGroup>().Where(x => projectGroupIds.Contains(x.Id)).Select(x => x.Id)
where projectIds.Contains(p.SurveyProjectId)
select p)
.Fetch(x => x.ShortLabels)
.Fetch(x => x.ReportingNames)
.Fetch(x => x.NormProject)
.ToList();
var response = new List<SurveyProjectNormDTO>();
queryResult.ForEach(p =>
response.Add(new SurveyProjectNormDTO {
Id = p.Id,
ProjectName = p.NormProject.ProjectName,
ReportingName = p.ReportingNames.Select(s => s.LocalizedText).FirstOrDefault() }));
return result;

How to specify Schema for Lists while mapping Nhibernate by code

I want my "tag_post" table to be created in "article" schema but it's created in "public" schema.
List(x => x.Tags, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});
I have never used mapping by code, but i assume this is the solution:
List(x => x.Students, l =>
{
l.Where("deleted = 0");
l.Key(k =>
{
k.Column("post_id");
k.NotNullable(true);
});
l.Schema(Constants.DatabaseSchemaNames.Article);
l.Table("tag_post");
}, x =>
{
x.ManyToMany(m => m.Column("tag_id"));
});

NHibernate and JoinAlias throw exception

I have query in HQL which works good:
var x =_session.CreateQuery("SELECT r FROM NHFolder f JOIN f.DocumentComputedRights r WHERE f.Id = " + rightsHolder.Id + " AND r.OrganisationalUnit.Id=" + person.Id);
var right = x.UniqueResult<NHDocumentComputedRight>();
Basically I receive NHDocumentComputedRight instance.
I've tried to implement the same query in QueryOver. I did this:
var right = _session.QueryOver<NHFolder>().JoinAlias(b => b.DocumentComputedRights, () => cp).Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp).List<NHDocumentComputedRight>();
But I get null reference exception.
How can I implement this query in QueryOver?
Update (added mappings) - NHibernate 3.2:
public class FolderMapping: ClassMapping<NHFolder>
{
public FolderMapping()
{
Table("Folders");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
Set(x => x.DocumentComputedRights, v =>
{
v.Table("DocumentComputedRightsFolder");
v.Cascade(Cascade.All | Cascade.DeleteOrphans);
v.Fetch(CollectionFetchMode.Subselect);
v.Lazy(CollectionLazy.Lazy);
}, h => h.ManyToMany());
Version(x => x.Version, map => map.Generated(VersionGeneration.Never));
}
}
public class DocumentComputedRightMapping : ClassMapping<NHDocumentComputedRight>
{
public DocumentComputedRightMapping()
{
Table("DocumentComputedRights");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
ManyToOne(x => x.OrganisationalUnit, map =>
{
map.Column("OrganisationalUnit");
map.NotNullable(false);
map.Cascade(Cascade.None);
});
}
}
public class OrganisationUnitMapping : ClassMapping<NHOrganisationalUnit>
{
public OrganisationUnitMapping()
{
Table("OrganisationalUnits");
Id(x => x.Id, map =>
{
map.Generator(IdGeneratorSelector.CreateGenerator());
});
//more not important properties...
}
}
Thanks
AFAIK criteria/queryOver can only return the entity it was created for (NHFolder in your example) or columns which are set to entity with aliastobean. you could do a correlated subquery instead.
var subquery = QueryOver.Of<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.Select(u => cp.Id);
var right = _session.QueryOver<NHDocumentComputedRight>()
.WithSubquery.Where(r => r.Id).Eq(subquery)
.SingleOrDefault<NHDocumentComputedRight>();
I think you have a problem with the select statement, have you tried something like this:
var right = _session.QueryOver<NHFolder>()
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(x => x.DocumentComputedRights)
.Where(h => h.Id == rightsHolder.Id && cp.OrganisationalUnit.Id == person.Id)
.List<NHDocumentComputedRight>();
This is what is working for me so it should work in you case as well.
I would guess that the main reason behind the problem is the lack of proper overload on the Select method. In reality you would like to write it like this:
.JoinAlias(b => b.DocumentComputedRights, () => cp)
.Select(() => cp)
but the Expression<Func<object>> is not there. Hopefully it's going to be included in the next version.