Saving C# enumeration as string instead of int in ElasticSearch 5 - elasticsearch

I used to have String attribute on class properties of type enumeration in Elastic Search 2.0 so that enumeration value to be stored as string rather than integer:
public enum PaperType
{
A4 = 0,
A3 = 1
}
and class to be stored as document in ElasticSearch
[ElasticsearchType(Name = "Paper")]
public class Paper
{
[String(Store = false, Index = FieldIndexOption.Analyzed)]
public string Name { get; set; }
[String(Store = false, Index = FieldIndexOption.Analyzed)]
public PaperType Type { get; set; }
}
So in Type would be stored as A3 or A4 rather than 0 or 1.
in ElasticSearch 5, these attributes have changed,
How could I achieve the same behavior in ElasticSearch 5 or what attribute and how it should be?
Thanks

Take a look at attribute mapping in the documentation; you're likely looking to map them as Keyword types.
If you want to save all enum as string, you can add the Json.Net StringEnumConverter to the JsonSerializerSettings to use for any type that is an enum.

Related

GraphQl Union input types

In HotChocolate I have a query type like so
// QueryType.cs
public Task<ContentCategory> FilterContentAsync(string categoryCode, ICollection<Filter> filters, CancellationToken cancellationToken = default)
=> ...;
// Filter.cs
public abstract class Filter
{
public string Type { get;set; }
}
// BooleanFilter.cs
public class BooleanFilter : Filter
{
public bool IsTrue { get; set; }
}
// NumberRangeFilter.cs
public class NumberRangeFilter : Filter
{
public int Min { get; set; }
public int Max { get; set; }
}
when I run the application I get the following error
1. Unable to infer or resolve a schema type from the type reference `Input: Filter`.
Is the following query supported:
filterContent (categoryCode: "All", filters: [{type: "boolean", isTrue: true}, {type: "numberrange", min: 10, max: 60}]) {
id
}
Seems that this is not implemented currently.
Here is an issue in hotchocolate repository. Currently (Jul 2021) it is open and have "backlog" label, so I can assume that input unions are not implemented yet.
And here is a tweet of one of developers of hotChocolate, where he says
We are implementing the #graphql oneof spec proposal for Hot Chocolate
12... let the input unions come :)
By the way there is another link to discussion about possible implementations for input union problem. So according to this, there is 7 various ideas how to change the spec, 1 winner (the 7th option) and no one single link to possible implementations.

C#9 + .NET5, nullable enabled: is it possible to use the object initialiser with non nullable properties without using null!?

I'm testing c# 9.0 with NET 5.0 and there is something I don't understand. I enabled <nullable>enable</nullable>.
If I write a class
public class Potato {
public string Colour { get; set; }
public string Flavour { get; set; }
}
I get the warning CS8618: Non-nullable propery 'Colour' must contain a non-null value when existing constructor. Consider declaring the propery as nullable. I do NOT want to declare it nullable, that's why I enabled the tag...
Then, I declare the constructor:
public class Potato
{
public Potato(string colour, string flavour)
{
this.Colour = colour;
this.Flavour = flavour;
}
public string Colour { get; set; }
public string Flavour { get; set; }
}
So far so good. Now I want to create a Potato object using the object initialiser:
var sweetPotato = new Potato {
Colour = "orange",
Flavour = "tasty",
};
And now I get the complain CS7036: There is no argument given that corresponds to the required formal parameter 'colour' of 'Potato.Potato(string, object). So, it tries to use the constructor I explicitly declared but I didn't introduce the parameters. I should do:
var sweetPotato = new Potato(
colour: "orange",
flavour: "tasty");
but here I am not using the object initialiser.
Another option would be declaring the class as
public class Potato
{
public string Colour { get; set; } = null!;
public string Flavour { get; set; } = null!;
}
with the null! elements, but this allows some weird things like:
var sweetPotato = new Potato()
{
Colour = "orange",
};
which I think it is extremely weird. I declared 2 non nullable properties and thanks to the null! I can load the object with one property but not loading the second one. That breaks my nullable tag!
Then my question is: is it possible to use the object initialiser with non nullable properties if the nullable tag is enabled?
If it is not, I think that for classes with non nullable properties, without any null! involved, the default constructor should not be the empty one but the one with all arguments, and it should have to be possible to init an object with the object initialiser form, as long as all non-nullable properties are initialised.
I know this is an old Question but here's the comprehensive answer:
by adding the <nullable>true<nullable> tag you make it so that all nullables must be identified with ?
because of 1., and since you didn't add ? to their types, neither Colour nor Flavour can be NULL
because of 2., you must supply a constructor that initializes values for both Colour and Flavour - the default parameterless constructor won't work as it does nothing by itself and would return an object with NULL in both Colour and Flavour, as that's the default for their types, which you requested the compiler not to allow
The snippet below:
var sweetPotato = new Potato {
Colour = "orange",
Flavour = "tasty",
};
uses the default parameterless constructor and so cannot be used. It is the shorthand equivalent to:
var sweetPotato = new Potato(); // sweetPotato has Colour and Flavour NULL
sweetPotato.Colour = "orange"; // sweetPotato still has Flavour NULL
sweetPotato.Flavour = "tasty";
which as you can see would create the object first (with default values) and assign values later. But by your not allowing the default value of NULL, it fails
And this is why if you won't allow them to be nullable, you must add a constructor that initializes them, and you must use that constructor
This wouldn't apply if their types were of a primitive that has a different default - like an int or a double. In that situation, the default parameterless constructor would work. But by using types with a default value of NULL, (like string or any object derived type), you can either make them nullable by adding ? or you must use a constructor that initializes them to something other than NULL.
Late, Late Edit
You can use the object initializer still if you introduce a parameterless constructor that defaults those two properties:
public Potato()
{
Colour = "blue";
Flavor = "bitter";
}
Then you can do:
var bitterPotato = new Potato(); //blue and bitter potato
var sweetPotato = new Potato
{
Color = "orange",
Flavour = "tasty"
}; // orange and tasty potato
The default value for string is null. As your property declarations do not define a default value, they will default to default, which happens to be null in the case of string. The problem is that you have not declared the type as nullable.
The solution is to assign a default value, such as String.Empty:
public class Potato
{
public string Colour { get; set; } = String.Empty;
public string Flavour { get; set; } = String.Empty;
}

Dynamic mapping in Nest 1.4

I am working on Nest version 1.4 . Currently I am handling csv files with column names varying in every new insertion. In order to do that I have to chamge my class name every now and then, eg suppose
Suppose there are only three fields in csv file like severity,entity_type and operation then I define my class like this
[ElasticProperty(Name = "severity", Store = true, Index = FieldIndexOption.NotAnalyzed, Type = FieldType.String)]
public string severity { get; set; }
[ElasticProperty(Name = "entity_type", Store = true, Index = FieldIndexOption.NotAnalyzed, Type = FieldType.String)]
public string entity_type { get; set; }
[ElasticProperty(Name = "operation", Store = true, Index = FieldIndexOption.NotAnalyzed, Type = FieldType.String)]
public string operation { get; set; }
But in another csv file i have a new field called "number", then again i need to add this attribute to this class which becomes tedious. Is there something called dynamic mapping in nest version 1.4 that can automatically map the column names from the csv files? Also I tried with MULTI-FIELD MAPPING but it doesnt seem to work. Please suggest.
Thanks
Nilanjana

Expression.Property(param, field) is "trolling" me [System.ArgumentException] = {"Instance property 'B.Name' is not defined for type A"}

Once again, I am facing an issue, this time with LINQ Expression builder and this time I am even struggling to find the reason why it's not working. I have a Database-First EF project with quite a few tables. For this specific case, I have to use 2 of them - DocHead and Contragent. MyService.metadata.cs looks like this:
[MetadataTypeAttribute(typeof(DocHead.DocHeadMetadata))]
public partial class DocHead
{
// This class allows you to attach custom attributes to properties
// of the DocHead class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class DocHeadMetadata
{
// Metadata classes are not meant to be instantiated.
private DocHeadMetadata()
{
}
public string doc_Code { get; set; }
public string doc_Name { get; set; }
public string doc_ContrCode { get; set; }
//...
[Include]
public Contragent Contragent { get; set; }
}
}
[MetadataTypeAttribute(typeof(Contragent.ContragentMetadata))]
public partial class Contragent
{
// This class allows you to attach custom attributes to properties
// of the Contragent class.
//
// For example, the following marks the Xyz property as a
// required property and specifies the format for valid values:
// [Required]
// [RegularExpression("[A-Z][A-Za-z0-9]*")]
// [StringLength(32)]
// public string Xyz { get; set; }
internal sealed class ContragentMetadata
{
// Metadata classes are not meant to be instantiated.
private ContragentMetadata()
{
}
public string Code { get; set; }
public string Name { get; set; }
//...
I take some docHeads like this:
IQueryable<DocHead> docHeads = new MyEntities().DocHead;
Then I try to sort them like this:
docHeads = docHeads.OrderByDescending(x => x.Contragent.Name);
It is all working like I want it. I get those docHeads sorted by the name of the joined Contragent. My problem is that I will have to sort them by a field, given as a string parameter. I need to be able to write something like this:
string field = "Contragent.Name";
string linq = "docHeads = docHeads.OrderByDescending(x => x." + field + ")";
IQueryable<DocHead> result = TheBestLinqLibraryInTheWorld.PrepareLinqQueryable(linq);
Unfortunately, TheBestLinqLibraryInTheWorld does not exist (for now). So, I have set up a method as a workaround.
public static IQueryable<T> OrderByField<T>(this IQueryable<T> q, string SortField, bool Ascending)
{
var param = Expression.Parameter(typeof(T), "x");
var prop = Expression.Property(param, SortField); // normally returns x.sortField
var exp = Expression.Lambda(prop, param); // normally returns x => x.sortField
string method = Ascending ? "OrderBy" : "OrderByDescending";
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp); // normally returns sth similar to q.OrderBy(x => x.sortField)
return q.Provider.CreateQuery<T>(mce);
}
Normally... yes, when it comes to own properties of the class DocHead - those prefixed with doc_. The disaster strikes when I call this method like this:
docHeads = docHeads.OrderByField<DocHead>("Contragent.Name", true); // true - let it be Ascending order
To be more specific, the exception in the title is thrown on line 2 of the method OrderByField():
var prop = Expression.Property(param, SortField);
In My.edmx (the model), the tables DocHead and Contragent have got a relation already set up for me, which is the following: 0..1 to *.
Once again, I have no problem writing "static" queries at all. I have no problem creating "dynamic" ones via the method OrderByField(), but only when it comes to properties of the class DocHead. When I try to order by a prop of the joined Contragent class - the disaster strikes. Any help will be greatly appretiated, thank you!
The problem is that Expression.Property method does not support nested properties. It does exactly what it says - creates expression that represents a property denoted by propertyName parameter of the object denoted by the expression parameter.
Luckily it can easily be extended. You can use the following simple Split / Aggregate trick anytime you need to create a nested property access expression:
var prop = SortField.Split('.').Aggregate((Expression)param, Expression.Property);

How does Protobuf-net support for Dictionary/KeyValuePair works?

I am trying to understand protobuf-net's Dictionary/KeyValuePair support. We would like to use the underlying binary stream and the generated proto file from java, but the generated .proto file contains what look like a custom type called Pair_String_Int32.
Can someone please shed some light on this?
I've got a class mapped like this:
[DataContract]
public class ForwardCurve
{
[DataMember(Order=1, IsRequired = true)]
public string Commodity { get; set; }
[DataMember(Order = 2, IsRequired = false)]
public IDictionary<string, int> DictValue { get; set; }
[DataMember(Order = 3, IsRequired = false)]
public IList<string> ListValue { get; set; }
}
The generated .proto file using Serializer.GetProto will be:
message ForwardCurve {
required string Commodity = 1;
repeated Pair_String_Int32 DictValue = 2;
repeated string ListValue = 3;
}
So what is Pair_String_Int32 (and what is going into the protobuffer byte stream) and is there any way of mapping this so that protobuf, by using protoc can create the equivalent mapping code in Java?
To get this for work add a new message to the generated .proto file that looks like this.
message Pair_String_Int32 {
required string Key = 1;
required int32 Value = 2;
}
Then protoc will be able to create the corresponding code for Java.
I can check later (I'm on iPod at the moment) but I believe is it simply a "repeated" set of a dummy type with members key=1 value=2 (using the default types for each - so c# string maps to proto string etc). I am in the process of re-implementing GetProto for v2, so I'll try to ensure these dummy types are included in the output.

Resources