I have created below object which will be mapped to ElasticSearch type. I would like to exclude the UnivId property from being indexed:
[ElasticType(Name = "Type1")]
public class Type1
{
// To be ignored
public string UnivId { get; set; }
[ElasticProperty(Name="Id")]
public int Id { get; set; }
[ElasticProperty(Name = "descSearch")]
public string descSearch { get; set; }
}
You should be able to set the OptOut value of the ElasticProperty attribute, like the following:
[ElasticProperty(OptOut = true)]
public string UnivId { get; set; }
In NEST 2.0 ElasticPropertyAttribute is replaced by per type attributes (StringAttribute, DateAttribute...). I used Ignore parameter to exclude property.
Exemple for string :
[String(Ignore = true)]
public string Id {get;set;}
If using Nest 5.0+, per the docs several ways to ignore a field:
Ignore attribute should work:
using Nest;
[Ignore]
public string UnivId { get; set; }
JsonIgnore can also be used since Newtonsoft.Json is the default serializer used by Nest.
Another way is to use type specific attribute mappings associated with the property. For example, since it's a string then use Text attribute:
[Text(Ignore = true)]
public string UnivId { get; set; }
or if an int use Number:
[Number(Ignore = true)]
public int Id { get; set; }
In addition, instead of using an explicit attribute on the property, the mapping can be ignored using .DefaultMappingFor<... on ConnectionSettings (see docs for more detail)
var connectionSettings = new ConnectionSettings()
.DefaultMappingFor<Type1>(m => m.Ignore(p => p.UnivId);
However, if want to conditionally ignore an attribute if the value is null then use the following Newtonsoft.Json attribute with null handling setting:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string UnivId { get; set; }
I found the above useful when doing partial updates on a doc but wanted to re-use the same C# class for indexing and avoid overwriting existing values in the index.
Related
I would like to retrieve a nested object from documents in my index called "userprofiles".
My UserProfile model:
public class UserProfileModel
{
public string FullName { get; set; }
public string Oid { get; set; }
public string Upn { get; set; }
public List<SsoLink> FavoriteSsoLinks { get; set; } = new List<SsoLink>();
}
My SsoLink Model:
public class SsoLink
{
public string Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Owner { get; set; }
}
Index creation:
PUT userprofiles
{
"mappings" : {
"properties" : {
"FavoriteSsoLinks" : {
"type" : "object"
}
}
}
}
My Query:
var searchResponse = _client.Search<UserProfileModel>(s => s
.Index(_profileIndex)
.Query(q=>q
.Term(t => t.Field(t => t.Oid).Value(oid)
)
)
);
Right now it returns the documents, but the favoritelinks object is blank, however I see objects listed from Kibana. I must be missing something obvious, but having trouble figuring this out.
Here is an example of my data:
Index creation example uses "FavoriteSsoLinks" as the property, but the Kibana screenshot uses "favoriteSsoLinks" starting with a lowercase f - which is correct? My suspicion is that property casing may be the issue, but would need to see the mapping in the index to know if this is correct.
The 7.x client is strict about property name casing in JSON, and by default uses camelcase property names to match to POCO property names. For example, by default
"favoriteSsoLinks" in JSON will be a match for FavoriteSsoLinks POCO property
"FavoriteSsoLinks" in JSON will not be a match for FavoriteSsoLinks POCO property
This behaviour can be changed with DefaultFieldNameInferrer(Func<string, string>) on ConnectionSettings for all properties, or on a property by property basis using attributes on properties such as DataMemberAttribute or PropertyNameAttribute, or using DefaultMappingFor<T> where T is the POCO type.
I have a string array that I want to deserialize. Essentially, it is just a list of objects. Note that the attributes have spaces in the names:
[ { \"Event Name\": \"Hurricane Irma PR\", \"Storm Start (LST)\": \"2017-08-30\", \"Storm End (LST)\": \"2017-09-13\", \"Grid Cell Number\": 16412, \"Grid Cell State\": \"PR\", \"Grid Cell Name\": \"Grid26_0\", ...
I created a public class to template the string based on specific attributes that I want ( I don't want all the data) but I am not sure how to handle for the spaces in the names of the attributes that I want.
public class New_Events_Dataset
{
public string EventName { get; set; }
public string StormStart { get; set; }
public string StormEnd { get; set; }
public string GridCellState { get; set; }
public string GridCellName { get; set; }
public string USGSGageSiteNo { get; set; }
public string ReturnPeriodatGridCell { get; set; }
}
When I apply the deserializer with my class New_Events_Dataset like this:
var jsonResponse = returnJson.Deserialize<List<New_Events_Dataset>>(strresult);
string json = new JavaScriptSerializer().Serialize(jsonResponse);
return json;
I end up returning something like this. What am I doing wrong?
[{"EventName":null,"StormStart":null,"StormEnd":null,"GridCellState":null,"GridCellName":null,"USGSGageSiteNo":null,"ReturnPeriodatGridCell":null}
Unfortunately keys must match exactly each other.
One of the best ways to solve your problem is to define JsonProperty attribute for each property to get Deserialized object correctly. You can specify property's json key name with it.
You can take a look to this question and it's answer for better understanding:
An example of JsonProperty
Edit:
As in comments mentioned, because you are using JavaScriptSerializer JsonPropertyAttribute doesn't work in this situation.
But you can use it by adding Newtonsoft.Json Nuget Package and using it's deserilizer this way:
JsonConvert.DeserializeObject<AzureResourceData>(jsonString);
I am using Entity Framework using Database first approach, but I am not using EDMX approach, instead I have my POCO classes defined and in the DBContext I am setting the initializer to NULL. So that it should not try to create objects in the database. Everything working very fine as expected.
In my POCO class I have properties wrapped by the StringLength attribute defined to a maximum length value for that property, just like below.
public class Users
{
[Key, Column(Order = 0)]
[XmlIgnore]
public long ID { get; set; }
[XmlIgnore]
[Key, Column(Order = 1)]
public long? SrNo { get; set; }
[XmlIgnore]
public DateTime ScanDateTime { get; set; }
[StringLength(255)]
[XmlElement(ElementName = "username")]
public string UserName { get; set; }
[StringLength(75)]
[XmlElement(ElementName = "lastlogon")]
public string LastLogon { get; set; }
[StringLength(75)]
[XmlElement(ElementName = "lastlogoff")]
public string LastLogoff { get; set; }
[StringLength(1000)]
[XmlElement(ElementName = "accountinfo")]
public string AccountInfo { get; set; }
[XmlIgnore]
public DateTime DCDTime { get; set; }
[XmlIgnore]
public DateTime? LastModDTime { get; set; }
}
I am using [XmlIgnore] attribute for XML deserialization. I do fill data into this class object by deserializing the XML data. In many of the cases XML may have data for the fields where the length of the data can exceed the StringLength defined in the POCO class.
I want to validate the data before sending a DB insert and getting failed from there.
I want to check and want to trim the data to the specified length as defined in the StringLength attribute property. For ex, after deserializing the XML data to Users object, if the username exceeds the 75 length then I will trim it to 75 and then pass the complete object for DB insert.
I know couple of ways of doing this and I am trying one as below by creating Extension method.
public static void ValidateData(this List<Users> Data)
{
int UserNamelength = typeof(Users).GetProperty("UserName ").GetCustomAttributes(typeof(StringLengthAttribute), false).Cast<StringLengthAttribute>().FirstOrDefault().MaximumLength;
foreach (var item in Data)
{
if (item.UserName.Length > UserNamelength )
{
//Trim the UserName field to the length i.e. 75 characters
}
}
}
Similarly I want the check to be on all the fields for Users class.
I am looking for any other simple and crisp solution.
Please help me with the same.
I would probably write custom deserialization code so that truncates the data from the XML into whatever size is specified in the model annotation. This is probably more work but in my opinion cleaner than validation. Just a thought.
say I have the attribute:
public class Column_Attribute : Attribute
{
public string DbType { get; set; }
public bool IsPrimaryKey { get; set; }
}
then I can apply that attribute to a property as:
[Column_Attribute(DbType = "Integer", IsPrimaryKey = true)]
public int Id { get; set; }
Now how can I get information about the property Id from the attribute class. In other words I want to do something like:
public class Column_Attribute : Attribute
{
// constructor
public Column_Attribute(){
// if the property has the name Id do something...
// OR
// if this is an attribute of a property do something
// if this is an attribute of a field do something else
// If this attribute is targeting a property that is a string do something
}
public string DbType { get; set; }
public bool IsPrimaryKey { get; set; }
}
I actually need to know if the attribute is being applied to a property that is a string.
I know how to do that with reflection but I want to do that inside the attribute class. Is that possible. Hope I am explaining myself correctly
You cannot do that without reflection because the code in the constructor will not be executed until you call GetCustomAttributes(), which is a part of reflection.
see http://msdn.microsoft.com/en-us/library/z919e8tw(v=vs.80).aspx
Calling GetCustomAttributes on SampleClass causes an Author object to
be constructed and initialized as above
If you want your attribute class to contain the processing code, you could create a method receiving the property name. The property name will be available at the time of calling GetCustomAttributes().
I'm looking for a simpler/drier way to use ressources my MVC 3 models.
This is how I'm doing it now (Each attribute needs to be told which ressource type it uses):
public class ContactMessageModel:BaseModel
{
[Display(Name="ReplyToEmail_DisplayName", ResourceType = typeof(Res.Views_Contact))]
public string ReplyToEmail {get; set; }
[Display(Name = "ContactReason_DisplayName", ResourceType = typeof(Res.Views_Contact))]
public string ContactReason { get; set; }
Can this be done?
This is how I'd like to do it (I just want to define the resource type for the model once):
[Display(ResourceType = typeof(Res.Views_Contact))]
public class ContactMessageModel:BaseModel
{
[Display(Name="ReplyToEmail_DisplayName")]
public string ReplyToEmail {get; set; }
[Display(Name = "ContactReason_DisplayName")]
public string ContactReason { get; set; }
Doesn't seem possible, because the attribute instance would require access to the property it is sitting on, which .NET does not support.
Yes, defaulting the ResourceType can be done. Phil Haack shows an example of how to override .NET's ModelMetadataProviders to accomplish this and prevent having to repeat yourself specifying the same ResourceType over and over:
http://haacked.com/archive/2011/07/14/model-metadata-and-validation-localization-using-conventions.aspx/
You can either default to a single ResourceType globally, or decorate specific classes with a default using this attribute he defines:
public class MetadataConventionsAttribute : Attribute
{
public Type ResourceType { get; set; }
}