how do we return all attributes of a node with neo4jclient? - dynamic

below code(search function) works fine.
public class BookItem
{
public string Title { get; set; }
public string OriginalTitle { get; set; }
}
public IEnumerable<dynamic> Search(string keyword)
{
/*MATCH (n:`Book`) RETURN n*/
var query = client
.Cypher
.Match("(n:Book)")
.Return(n => n.As<BookItem>());
return query.Results;
}
However, i don't want to declare a class like BookItem. I just want all results in a dynamic object. Is there a way to do that?
For example below code runs and returns empty object, it doesn't return any attributes..
public IEnumerable<dynamic> Search(string keyword)
{
/*MATCH (n:`Book`) RETURN n*/
var query = client
.Cypher
.Match("(n:Book)")
.Return(n => n.As<dynamic>());
return query.Results;
}

The basic gist is in the answer to this question: Casting nodes of an unknown type
What you end up returning is Node<string> and parsing using Json.net into a dynamic object, there is no direct way of just doing x.As<dynamic>() unfortunately.

Related

Blazor sanitize MarkupString

I'm trying to sanitize content of MarkupString. Actually I created this (based from https://github.com/dotnet/aspnetcore/blob/574be0d22c1678ed5f6db990aec78b4db587b267/src/Components/Components/src/MarkupString.cs)
public struct MarkupStringSanitized
{
public MarkupStringSanitized(string value)
{
Value = value.Sanitize();
}
public string Value { get; }
public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);
public override string ToString() => Value ?? string.Empty;
}
But render output isn't raw html. How should I implement MarkupStringSanitized to use
#((MarkupStringSanitized)"Sanitize this content")
Couple of suggestions (Not necessarily for OP, but for anyone else looking to solve the problem):
You didn't provide the code that does the actual sanitization, so I'm going to state the (hopefully) obvious best practice and if you're following it, great. Do not use Regular Expressions (Regex) to parse HTML
Also, the Sanitize() method should follow the pattern of immutability in this case
I would suggest the following library Gans.XSS.HtmlSanitizer which is an active library and updated regularly.
The problem
Razor View Engine can doesn't know how to render a MarkupStringSanitized. Just because you duck typed a sanitized version of the same struct doesn't mean it can render it. To get this to render, you'll need to cast it to something it does know, MarkupString
Here's what happens when I used your HtmlSanitizedMarkup directly with no modifications.
#((MarkupStringSanitized)Content)
Working Example #1
Here's an example using my Markdown -> Html playground (fully tested and working):
MarkupStringSanitized.cs
public struct MarkupStringSanitized
{
public MarkupStringSanitized(string value)
{
Value = Sanitize(value);
}
public string Value { get; }
public static explicit operator MarkupStringSanitized(string value) => new MarkupStringSanitized(value);
public static explicit operator MarkupString(MarkupStringSanitized value) => new MarkupString(value.Value);
public override string ToString() => Value ?? string.Empty;
private static string Sanitize(string value) {
var sanitizer = new HtmlSanitizer();
return sanitizer.Sanitize(value);
}
}
MarkupStringSanitizedComponent.razor
#if (Content == null)
{
<span>Loading...</span>
}
else
{
#((MarkupString)(MarkupStringSanitized)Content)
}
#code {
[Parameter] public string Content { get; set; }
}
That extra conversion though is ugly IMO. (maybe someone smarter than me can clean that up?)
Working example #2
Here I tried extending the MarkupString with an extension method. It looks a little better, but only a little.
MarkupStringExtensions.cs
public static class MarkupStringExtensions
{
public static MarkupString Sanitize(this MarkupString markupString)
{
return new MarkupString(SanitizeInput(markupString.Value));
}
private static string SanitizeInput(string value)
{
var sanitizer = new HtmlSanitizer();
return sanitizer.Sanitize(value);
}
}
MarkupStringSanitizedComponent.razor
#if (Content == null)
{
<span>Loading...</span>
}
else
{
#(((MarkupString)Content).Sanitize())
}
#code {
[Parameter] public string Content { get; set; }
}

How to create MatchQueryDescriptor using field name as a string?

After upgrading Nest from 5.4 to 6.2 I could not find the right syntax to create MatchPhraseQueryDescriptor using known field name as a string. It appears that .Field() method no longer takes a string but takes an object path instead.
What is the easiest way to re-write following Nest 5.4 snippet for Nest 6.2 ?
var matchPhrase = new MatchPhraseQueryDescriptor<MyType>()
.Field("MyField")
.Query("MyQuery");
?
MatchPhraseQueryDescriptor<T> accepts Field or Expression<Func<T, object>> as parameters to .Field(...), which it inherits from FieldNameQueryDescriptorBase:
public abstract class FieldNameQueryDescriptorBase<TDescriptor, TInterface, T>
: QueryDescriptorBase<TDescriptor, TInterface>, IFieldNameQuery
where TDescriptor : FieldNameQueryDescriptorBase<TDescriptor, TInterface, T>, TInterface
where TInterface : class, IFieldNameQuery
where T : class
{
Field IFieldNameQuery.Field { get; set; }
bool IQuery.IsVerbatim { get; set; }
bool IQuery.IsStrict { get; set; }
public TDescriptor Field(Field field) => Assign(a => a.Field = field);
public TDescriptor Field(Expression<Func<T, object>> objectPath) =>
Assign(a => a.Field = objectPath);
}
There is an implicit operator that converts from string to Field.

Return true/false along with model data

I'm attempting to return a true or false (in JSON) along with my model data. Code builds and runs fine but I only get a return on my model data.
What I've tried from reading other answers:
public IQueryable<Book> GetBooks()
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
return db.Books;
}
As you can probably easily see, I don't have the greatest idea of what I'm doing, but through the infinite wisom of this community I hope to learn another feat.
I would create a view model and returned that from the controller
public class BooksVm
{
public IQueryable<Book> Books { get; set; }
public bool BooleanValue { get; set; }
}
and then in your controller
public IHttpActionResult GetBooks()
{
var booksVm = new BooksVm() { Books = db.Books, BooleanValue = true };
return Ok(booksVm);
}

Persisting Part Record to Database

Working on creating my first Orchard Module and I am running into issues getting the form data saved back to the database. I have everything registered correctly as far as I can tell from looking at a lot of samples so I must be missing something minor.
I am able to get the Apartment form to show under the new menu, validation is working but when I fill the form completly and hit save I get:
Your Apartment has been created.
Checking the database the record is not in the table and checking the logs shows:
2013-12-19 09:15:23,416 [19]
NHibernate.Transaction.ITransactionFactory - DTC transaction prepre
phase failed NHibernate.Exceptions.GenericADOException: could not
execute batch command.[SQL: SQL not available] --->
System.Data.SqlClient.SqlException: Cannot insert the value NULL into
column 'FloorPlanName', table
'Orchard.dbo.CommunityWebsiteSolutions_ApartmentPartRecord';
column does not allow nulls. INSERT fails.
Running SQL Profiler shows an insert with all columns being set to NULL.
Migrations.cs
SchemaBuilder.CreateTable(typeof(ApartmentPartRecord).Name, table => table
.ContentPartRecord()
.Column<string>("FloorPlanName", c => c.WithLength(25).NotNull())
.Column<string>("FullAddress", c => c.WithLength(256).NotNull()))
.Column<string>("ShortDescription", c => c.WithLength(150).NotNull())
.Column("NumberOfBedrooms", DbType.Int32, c => c.NotNull())
.Column("NumberOfBathrooms", DbType.Int32, c => c.NotNull())
.Column("SquareFootage", DbType.Int32, c => c.NotNull())
.Column("WhenAvailable", DbType.DateTime)
.Column("RentAmount", DbType.Decimal)
);
ContentDefinitionManager.AlterPartDefinition(typeof (ApartmentPart).Name, part => part.Attachable());
ApartmentPart
public class ApartmentPartRecord : ContentPartRecord {
public virtual string FloorPlanName { get; set; }
public virtual string ShortDescription { get; set; }
public virtual string FullAddress { get; set; }
public virtual int? NumberOfBedrooms { get; set; }
public virtual int? NumberOfBathrooms { get; set; }
public virtual int? SquareFootage { get; set; }
public virtual DateTime? WhenAvailable { get; set; }
public virtual decimal? RentAmount { get; set; }
}
public class ApartmentPart : ContentPart<ApartmentPartRecord> {
[Required, StringLength(256)]
[Display(Name = "Address / Unit Number")]
public string FullAddress {
get { return Record.FullAddress; }
set { Record.FullAddress = value; }
}
[Required, StringLength(25)]
[Display(Name = "Floor Plan")]
public string FloorPlanName {
get { return Record.FloorPlanName; }
set { Record.FloorPlanName = value; }
}
[Required, StringLength(150)]
[Display(Name = "Sales Description")]
public string ShortDescription {
get { return Record.ShortDescription; }
set { Record.ShortDescription = value; }
}
[Required]
[Display(Name = "Bedroom Count")]
public int? NumberOfBedrooms {
get { return Record.NumberOfBedrooms; }
set { Record.NumberOfBedrooms = value; }
}
[Required]
[Display(Name = "Bathroom Count")]
public int? NumberOfBathrooms {
get { return Record.NumberOfBathrooms; }
set { Record.NumberOfBathrooms = value; }
}
[Required]
[Display(Name = "Square Footage")]
public int? SquareFootage {
get { return Record.SquareFootage; }
set { Record.SquareFootage = value; }
}
[Display(Name = "First Availability")]
public DateTime? WhenAvailable {
get { return Record.WhenAvailable; }
set { Record.WhenAvailable = value; }
}
[Display(Name = "Rent Amount")]
public decimal? RentAmount {
get { return Record.RentAmount; }
set { Record.RentAmount = value; }
}
}
Driver
public class ApartmentPartDriver : ContentPartDriver<ApartmentPart>
{
protected override string Prefix
{
get { return "Apartment"; }
}
//GET
protected override DriverResult Editor(ApartmentPart part, dynamic shapeHelper)
{
return ContentShape("Parts_Apartment_Edit",
() => shapeHelper.EditorTemplate(
TemplateName: "Parts/Apartment",
Model: part,
Prefix: Prefix));
}
//POST
protected override DriverResult Editor(ApartmentPart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
Handler
public class ApartmentPartHandler : ContentHandler {
public ApartmentPartHandler(IRepository<ApartmentPartRecord> repository)
{
Filters.Add(StorageFilter.For(repository));
}
}
Your error message explains this pretty clearly:
System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'FloorPlanName', table 'Orchard.dbo.CommunityWebsiteSolutions_ApartmentPartRecord'; column does not allow nulls. INSERT fails.
Your problem occurs because:
You are using nullable types such as string and int? types in your Record class, which means you want to allow nulls.
Yet, you are specifying in your DB migration that you want to disallow nulls.
And when C# instantiates your Record class, it initializes the fields using the default value, which is null for nullable types.
You can do one of the following:
Make your DB columns nullable (remove NotNull)
Make your Record class use non-nullable types (for example, int instead of int?). Note that this is not an option for reference types such as string.
Give non-null default values to the fields of your Record class by giving the class a constructor. This is arguably bad practice since you will be calling virtual properties in a base class, but seems to be ok in NHibernate.
Give non-null default values to the fields of your Record class by giving your part an OnInitializing handler, which would be placed in your Handler class.
UPDATE
You commented that you are expecting the fields to be filled in by the TryUpdateModel in the Editor function of your driver class. This does eventually happen, but the actual sequence of events that occurs is this (you can see this in the CreatePOST method of Orchard.Core.Contents.Controllers.AdminController):
ContentManager.New() with the content type ID to create content item in memory. This step calls OnInitializing for the appropriate content parts for the content type, which are defined in handlers.
ContentManager.Create() with the content item in Draft Mode. This step actually tries to persist the item to the DB once.
ContentManager.UpdateEditor(). This is the call that actually calls Editor of the appropriate driver for the content type.
Check the ModelState and roll back the transaction if anything has failed.
Step 2 will fail if you have NULL values in columns marked NotNull, because the fields have default values at that point. For these columns, you have to fill them in before step 2 by using OnInitializing or by using a constructor on your Record part.
In other words, TryUpdateModel in your driver is actually applying changes directly to the entity that has already been Created and is now attached to the NHibernate session.

Value Injecter : Dto to Domain Model (NHibernate)

I am using ValueInjecter to map properties from a Domain model to a DTO served up via a Service Layer. The service in question also accepts updates... so an updated DTO is passed in and this is then injected to the domain object and saved.
// Domain
public class Member
{
public Country Country { get; set; }
}
public class Country
{
public string Code { get; set; }
public string Name { get; set; }
}
//Dto
public class MemberDto
{
public string CountryCode { get; set; }
}
//Transformation Method attempt 1
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto);
return source;
}
Now all this above code does is updates the Property Member.Country.Code which is obviously not what I need it to do.
So from the docs, I figured I needed to create an override and got this:
public class CountryLookup: UnflatLoopValueInjection<string, Country>
{
protected override Country SetValue(string sourcePropertyValue)
{
return countryService.LookupCode(sourcePropertyValue);
}
}
//revised transformation call
//Transformation Method attempt 2
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto)
.InjectFrom<CountryLookup>(dto);
return source;
}
My problem is during debugging, CountryLookup never gets called.
Possible reasons I can think of:
Nhibernate Proxy classes causing value injecter to not match the Country type? Tho this doesnt make sense because it works during the flattening.
Perhaps the unflattening isn't firing for some reason. I.e Dto is CountryCode and Domain is Country.Code
I need to use the CountryCode property on the Dto to call a countryService.LookupCode to return the correct object to use during the update injection.
unflattening would be to do this:
entity.Country.Code <- dto.CountryCode
what you need is:
entity.Country <- dto.CountryCode
so the solution for you would be to inherit an ExactValueInjection where you would go from CountryCode to Country.
what I recommend you to do is do the same that I did in the live demo of another project of mine http://awesome.codeplex.com
where I have something like this:
public class Entity
{
public int Id{get;set;}
}
public class Member : Entity
{
public Country Country{get;set;}
}
public class MemberDto : DtoWithId
{
public int? Country {get;set;}
}
and use these injections to go from entity to dto and back
public class NullIntToEntity : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType == typeof(int?) && targetType.IsSubclassOf(typeof(Entity));
}
protected override object SetValue(object sourcePropertyValue)
{
if (sourcePropertyValue == null) return null;
var id = ((int?) sourcePropertyValue).Value;
dynamic repo = IoC.Resolve(typeof(IRepo<>).MakeGenericType(TargetPropType));
return repo.Get(id);
}
}
//(you also need to have a generic repository, notice IRepo<>)
public class EntityToNullInt : LoopValueInjection
{
protected override bool TypesMatch(Type sourceType, Type targetType)
{
return sourceType.IsSubclassOf(typeof (Entity)) && targetType == typeof (int?);
}
protected override object SetValue(object o)
{
if (o == null) return null;
return (o as Entity).Id;
}
}
these injections will handle not just going from int? to Country and back but also any other type which inherits Entity
Using the suggestion/reference from Omu this was the specific code to the problem.
public class CountryLookup : ExactValueInjection
{
private ICountryService countryservice;
public CountryLookup(ICountryService countryService)
{
this.countryService = countryService;
}
protected override bool TypesMatch(Type s, Type t)
{
return (s == typeof(string)) && (t == typeof (Country));
}
protected override Object SetValue(object v)
{
if (v == null)
return null;
var country = countryService.LookupCode((string) v);
return country;
}
public override string SourceName()
{
return "CountryCode";
}
public override string TargetName()
{
return "Country";
}
}
public Member InjectFromDto (MemberDto dto, Member source)
{
source = source.InjectFrom<UnflatLoopValueInjection>(dto)
.InjectFrom<CountryLookup>(dto);
return source;
}
Is a framework calling the setter method? In most DI frameworks, the standard is lowercase 's' in the setMethod(). Just a first-thought recommendation.