Using the NHibernate QueryOver, how can you add a type-safe restrictions between dates - nhibernate

Considering the following QueryOver (quarter and centre are variables passed in):
QueryOver.Of<Activity>()
.Where(Restrictions.On<Activity>(a => a.StartDate).IsBetween(quarter.StartDate).And(quarter.EndDate) ||
Restrictions.On<Activity>(a => a.EndDate).IsBetween(quarter.StartDate).And(quarter.EndDate) ||
Restrictions.And(Restrictions.Lt("StartDate", quarter.StartDate), Restrictions.Gt("EndDate", quarter.EndDate))) //TODO: Refactor this to remove magic strings
.And(a => a.Centre == centre)
.OrderBy(a => a.Title).Asc;
This query works perfectly, but I'd like to change the following restriction to remove the magic strings:
Restrictions.And(Restrictions.Lt("StartDate", quarter.StartDate), Restrictions.Gt("EndDate", quarter.EndDate))
Here are the entities (snipped for brevity):
public class Quarter
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
public class Activity
{
public string Title { get; set; }
public Centre Centre { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
public class Centre
{
public string Name { get; set; }
}
So what is the type-safe way using the new QueryOver extensions that will enable me to remove these magic strings?

This is what you want:
Restrictions.And(
Restrictions.Lt(Projections.Property<Activity>(x => x.StartDate),
quarter.StartDate),
Restrictions.Gt(Projections.Property<Activity>(x => x.EndDate),
quarter.EndDate)))
Sidenote: property names are not magic strings.

Related

Adding [ResultColumn] to Database.tt in PetaPoco

I am an avid user of PetaPoco. Is there any way to tweak the Database.tt (for generation of POCO's) to specify a ResultColumn in a specific table?
TIA
Currently, the Database.tt states:
// Tweak Schema
tables["tablename"].Ignore = true; // To ignore a table
tables["tablename"].ClassName = "newname"; // To change the class name of a table
tables["tablename"]["columnname"].Ignore = true; // To ignore a column
tables["tablename"]["columnname"].PropertyName="newname"; // To change the property name of a column
tables["tablename"]["columnname"].PropertyType="bool"; // To change the property type of a column
I do not know how to change the template, other then these instructions (which work very well). I was hoping for a similar statement that could produce a POCO like:
[TableName("phoenix.view_medical_records")]
[ExplicitColumns]
public partial class view_medical_records
{
[Column] public string lastname { get; set; }
[Column] public string firstname { get; set; }
[Column] public string birthdate { get; set; }
[Column] public int? chart_number { get; set; }
[ResultColumn] public DateTime tservice { get; set; }
[Column] public string status { get; set; }
[ResultColumn] public DateTime tcompleted { get; set; }
[Column] public string procedure_description { get; set; }
[Column] public string description { get; set; }
[Column] public string provider { get; set; }
}
Note: the [ResultColumn] attribute being automatically supplied?!
Thanks.
As per my comment on the question, PetaPoco doesn't support result columns via the T4 generator files. However, a workaround would be to ignore the columns
tables["phoenix.view_medical_records"]["tservice"].Ignore = true;
tables["phoenix.view_medical_records"]["tcompleted"].Ignore = true;
And, supply partial classes for the generated one which supply the columns.
public partial Poco1
{
// Generated by PP
}
public partial Poco1
{
// Supplied by the developer (Must be in same namespace)
[ResultColumn] public DateTime tservice { get; set; }
[ResultColumn] public DateTime tcompleted { get; set; }
}

Handling queries over related documents in RavenDB

I have a project where I have a set of forms:
public class Form
{
public string Id { get; set; }
public string Name { get; set; }
public IList<string> FieldValueIds { get; set; }
public string UserId { get; set; } // the user who completed the form.
public string FormTemplateId { get; set; }
}
Which each "implement" a form template selected at creation of the form.
public class FormTemplate
{
public string Id { get; set; }
public string Name { get; set; }
public IList<string> FieldIds { get; set; }
}
Which defines which fields are present within the form. Each field
public class FormField
{
public string Id { get; set; }
public string Name { get; set; }
public string Caption { get; set; }
public ValueType DataType { get; set; } // Enum specifying the type of data this field accepts.
}
Stores information about the field such as a description and what type it is expecting. Each FormField can be present in multiple FormTemplates with the values for the form being stored as FieldValue objects related to the Form itself.
public class FieldValue
{
public string Id { get; set; }
public string FieldId { get; set; }
public string ValueAsJsonString { get; set; }
}
Other objects include the User Object:
public class User
{
public string Id { get; set; }
public string Username { get; set; }
public string GivenNames { get; set; }
public string Surname { get; set; }
}
I would like to be able to perform a query to find all Forms completed by a user with a specified name, or all Forms where a field with name X has value Y and so forth.
I have looked into usage of indexes as specified in the documentation Indexing related documents, however the implementation as presented in the documentation threw a NotSupportedException when I implemented the example as follows:
class FormTemplates_ByFieldAndName : AbstractIndexCreationTask<FormTemplate>
{
public class Result
{
public string Name { get; set; }
public IList<string> FieldNames { get; set; }
}
public FormTemplates_ByFieldAndName()
{
Map = FormTemplates => from FormTemplate in FormTemplates
select new
{
Name = FormTemplate.Name,
FieldNames = FormTemplate.FieldIds.Select(x => LoadDocument<FormField>(x).Name)
};
}
}
// in code:
IList<FormTemplate> TestResults = session.Query<FormTemplates_ByFieldAndName.Result, FormTemplates_ByFieldAndName>()
.Where(x => x.Name == "TemplateName" || x.FieldNames.Contains("FieldName"))
.OfType<FormTemplate>()
.ToList();
As best as I can tell this was implemented correctly, however I have seen a suggestion to replace the .Contains with a .Any implementation instead. In lieu of this I have been experimenting with a different approach by applying successive .Where arguments. Like so:
var pre = session.Query<FormTemplates_ByFieldAndName.Result, FormTemplates_ByFieldAndName>();
var pr2 = pre.Where(x => x.Name == "TypeTest25");
List<FormTemplate> TestResults = pr2
.Where(x => x.FieldNames.Any(a => a == "field25"))
.OfType<FormTemplate>()
.OrderByScoreDescending()
.ToList();
Modifying the system to perform in a more factory oriented approach by applying successive filters based on a supplied string in a pre-specified format.
Is this the way I should be going for this implementation and if not what should I be changing? In particular if I am to proceed with the Indexing option how would I apply this technique to the nested relationship between Forms and FormFields through FormTemplates.
You seems to be trying to do this in a way that is mostly relational, but you don't have to.
Instead of trying to have a set of independent documents that each has part of the data, just store it all in a single document.
public class Form
{
public string Id { get; set; }
public string Name { get; set; }
public IList<FieldValue> FieldValues { get; set; }
public string UserId { get; set; } // the user who completed the form.
public string FormTemplateId { get; set; }
}
public class FieldValue
{
public string Id { get; set; }
// can store the value directly!
//public string ValueAsJsonString { get; set; }
public object Value {get; set; }
}
This will generate documents that looks like this:
{
"Id": "forms/1234",
"Name": "Tom",
"FieldValues": [
{
"Id": "FromValues/SchoolDistrictName",
"Value": "ABi195"
}
],
"UserId": "users/tom",
"FormTemplateId": "FromTemplate/1234"
}
Which is a much more natural way to model things.
At that point, you can use RavenDB's ability to index dynamic data, see the docs here:
https://ravendb.net/docs/article-page/3.5/Csharp/indexes/using-dynamic-fields

Linq not seeing properties

I have the following class and I'm trying to access it's properties from a different related class as follows:
var nuInfo = recipe.RECIPE_INGREDIENT
.Select(i => i.INGREDIENT.INGREDIENT_NUTRITIONAL_INFO)
.Where(ni => ni.NUTRITIONAL_INFO.Main == 1);
However, I can't access any (virtual or not) properties of INGREDIENT_NUTRITIONAL_INFO.
The INGREDIENT_NUTRITIONAL_INFO class is as follows:
public class INGREDIENT_NUTRITIONAL_INFO
{
public int IngredientId { get; set; }
public int Nutritional_InfoId { get; set; }
public double Amount { get; set; }
public DateTime DateSubmitted { get; set; }
public DateTime DateModified { get; set; }
public string SubmittedBy { get; set; }
public string ModifiedBy { get; set; }
public virtual AspNetUsers AspNetUsers { get; set; }
public virtual AspNetUsers AspNetUsers1 { get; set; }
public virtual INGREDIENT INGREDIENT { get; set; }
public virtual NUTRITIONAL_INFO NUTRITIONAL_INFO { get; set; }
}
Error Code is as follows:
CS1061 'ICollection' does not contain a definition for 'NUTRITIONAL_INFO' and no extension method 'NUTRITIONAL_INFO' accepting a first argument of type 'ICollection' could be found (are you missing a using directive or an assembly reference?)
Am I missing something in Linq? Am I trying to traverse across too many relationships?
The error is because you're not adding .First() or .FirstOrDefault() on the end of your query:
var nuInfo = recipe.RECIPE_INGREDIENT.Select(i => i.INGREDIENT.INGREDIENT_NUTRITIONAL_INFO)
.Where(ni => ni.NUTRITIONAL_INFO.Main == 1)
Your code is trying to access NUTRITIONAL_INFO as a property of the collection, not as the property of a member in the collection.
The problem is that nuInfo is not just one INGREDIENT_NUTRITIONAL_INFO object, your LINQ query returns a result as a IEnumerable<T>.
If you want to get a single result you can use First(),FirstOrDeafult, Single() or SingleOrDefault to instead return a single result.
var nuInfo = recipe.RECIPE_INGREDIENT
.Select(i => i.INGREDIENT.INGREDIENT_NUTRITIONAL_INFO)
.FirstOrDefault(ni => ni.NUTRITIONAL_INFO.Main == 1);

Linq with EF, include specific columns

I have two classes:
public class Category
{
public int Id { get; set; }
[Required]
[MaxLength(255)]
public string Name { get; set; }
public int? CategoryId { get; set; }
public double Weight { get; set; }
public ICollection<Article> Articles { get; set; }
public bool Hidden { get; set; }
}
public class Article
{
public int Id { get; set; }
[StringLength(255)]
public string Title { get; set; }
public string Body { get; set; }
public double Weight { get; set; }
public Category Category { get; set; }
public int? CategoryId { get; set; }
}
I would like to select some Categories including Articles, but without Article.Body. Method syntax is more preferred.
Something like:
IEnumerable<Category> categories = _context
.Categories
.Where(c => c.Hidden == false)
.Include(c => c.Articles)
.OrderBy(c => c.Weight);
Not sure how to specify which columns exactly to select (eagerly) on the included Articles.
Include doesn't allow projections, you can only include complete entities.
But there is a way out.
This is a typical case that you should solve by table splitting. By table splitting you "split" a table over two (or more) entities, so it's easier to filter e.g. light data from heavy data or public data from secure data.
In your case the class model (for Article) would look like this:
public class Article
{
public int Id { get; set; }
[StringLength(255)]
public string Title { get; set; }
public double Weight { get; set; }
public Category Category { get; set; }
public int? CategoryId { get; set; }
public virtual ArticleBody ArticleBody { get; set; }
}
public class ArticleBody
{
public int Id { get; set; }
public string Text { get; set; }
}
And the mappings:
modelBuilder.Entity<Article>()
.HasRequired(a => a.ArticleBody)
.WithRequiredPrincipal();
modelBuilder.Entity<Client>().ToTable("Article");
modelBuilder.Entity<ArticleBody>().ToTable("Article");
Now if you do...
_context.Categories
.Where(c => !c.Hidden)
.Include(c => c.Articles)
...you'll see that only Articles without body texts will be selected in the generated SQL.
If you want the body as well, you do
_context.Categories
.Where(c => !c.Hidden)
.Include(c => c.Articles.Select(a => a.ArticleBody))
Sorry if i did not understand your question, but I think you can specify what columns you want in your select statement.
Simple example:
var query = from c in Categories
select c.Name, c.CategoryId;

Is there a method to choose only some specific fields of a table using Automapper or EntityFramework?

I have a table in SqlServerDatabase. Table name is User(Id,Name,Paswd) and Im using automapper in Mvc4. Now i want only specific fields or 2 fields from the table instead of whole table, using automapper.how to do??
basically if the 2 objects have the same fields as in the little example
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Paswd { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public string Paswd { get; set; }
}
You just have to ignore the field
Mapper.CreateMap<User, UserDto>()
.ForMember(o => o.Paswd, m => m.Ignore());
You can find a lot of usefull example and features here
Automapepr Wiki