I am using Nest 6.2.0 to connect to elastic search.
I am trying to map a class containing DBGeography objects and I have tried adding the [GeoShape] tag and I get the following error.
ServerError = {ServerError: 400Type: mapper_parsing_exception Reason: "failed to parse" CausedBy: "Type: not_x_content_exception Reason: "Compressor detection can only be called on some xcontent bytes or compressed xcontent bytes""}
The code I am using to Create the index and document are:
// Create an index
response = Connection.CreateIndex(indexName, c => c
.Mappings(ms => ms
.Map<RACE.DataModels.EventModels.Event.Route>(m => m
.AutoMap<RACE.DataModels.EventModels.Event.Route>()
)
)
);
// Add document to index
result = Connection.Index(obj, i => i
.Index(indexName));
Also, here is the code for the Route object which I am trying to add to the index.
public partial class Route : BaseClass
{
[Key]
public Guid ID { get; set; }
[Required]
[Display(Name = "Event")]
public Guid EventID { get; set; }
[Required]
[Display(Name = "Route Name")]
public string Name { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Required]
[Display(Name = "Path Type")]
public int PathType { get; set; }
[GeoShape]
[Required]
[Display(Name = "Route Path")]
public DbGeography Path { get; set; }
//[GeoShape]
[Ignore]
public string PathWKT { get { return Path.WellKnownValue.WellKnownText; } }
[GeoShape]
[Display(Name = "Start")]
public DbGeography Start { get; set; }
[GeoShape]
[Display(Name = "End")]
public DbGeography End { get; set; }
[Display(Name = "Laps")]
public int Laps { get; set; }
[Display(Name = "Status")]
public int Status { get; set; }
[Ignore]
[ForeignKey("EventID")]
public virtual Event Event { get; set; }
[Ignore]
[ForeignKey("RouteID")]
public virtual List<Gateway> Gateways { get; set; }
}
Is DBGeography stopping the object from being correctly mapped, and how can I correctly map a DBGeography object to GeoShape?
NEST doesn't know how to serialize DbGeography types. The options you have are:
Write a JsonConverter that can serialize a DbGeography to geo_shape geoJSON that Elasticsearch supports, and hook up JsonNetSerializer from Nest.JsonNetSerializer nuget package to use this converter.
or
Map the DbGeography type to the respective IGeoShape type that NEST knows how to serialize, and use IGeoShape on your document POCO. You could probably leverage NetTopologySuite and types such as WKTReader to help with the conversion.
Elasticsearch 6.2.0 supports geo_shape input as WKT but this is not yet exposed in NEST; there's an open issue to add it in the next release. At the very least, I expect this to support deserializing WKT to NEST's IGeoShape.
Related
This is the class:
namespace backend
{
[Table("Products")]
public class Product
{
public long Id { get; set; }
[Required]
public string? Name { get; set; }
public string? Category { get; set; }
public string? Short { get; set; }
public string? Description { get; set; }
[Required]
public float Price { get; set; }
public string? MainImage { get; set; }
public float Disccount { get; set; }
public string[]? Images { get; set; } // List<string>
}
}
I've tried to run EF migrations but it appears that [] is not supported and, if I make it a List, it will ask for this List's key but it's just an array of strings
What am I doing wrong? Is not possible to add arrays as classes properties in EF?
It depends on the use case. Does the data be used in a relational child table way (1:many)? Or is it really just a list of some urls that don't have any further relations within the database?
For the first case, take a look at Caius answer. The second approach would be to write a type converter and register it within EF core. In that case your underlying type in the database would be some kind of string (e.g. nvarchar(max)) and EF core makes the conversion on the client side
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<Product>()
.Property(e => e.Images)
.HasConversion(
v => JsonSerializer.Serialize(v),
v => JsonSerializer.Deserialize<string[]>(v));
}
Instead of JSON you could also use some other approach like string.Join() and string.Split(), that's up to you. Further information can be found at Microsoft documentation.
What's wrong with doing what a relational database would expect:
namespace backend
{
[Table("Products")]
public class Product
{
public long Id { get; set; }
[Required]
public string? Name { get; set; }
public string? Category { get; set; }
public string? Short { get; set; }
public string? Description { get; set; }
[Required]
public float Price { get; set; }
public string? MainImage { get; set; }
public float Disccount { get; set; }
public ICollection<ProductImage>? Images { get; set; } //make it a new hashset in the constructor, btw
}
[Table("ProductImages")]
public class ProductImage
{
public long Id { get; set; }
[Required]
public string? Name { get; set; }
public string? Url { get; set; }
public long ProductId { get; set; }
public Product? Product { get; set; }
}
this way you can add more data to the image, like "front view", "side view", "version 2" etc, and EF can map it like it knows how to; as a separate table that is 1:M related
Is not possible to add arrays as classes properties in EF?
Technically, the ICollection<ProductImage> is a property that is an "array".. but out-of-the-box, not arrays of primitives, no
string is primitive type. you can't save list of primitive types in entity framework instead you can save your data in one property which is a single string then define another property to just get and set the main string property.
public class example {
public string AttachmentsString { get ; set; }
[NotMapped]
public List<string> Attachments {
get => !string.IsNullOrEmpty(AttachmentsString) ? AttachmentsString.Split(",").ToList() : new List<string>();
set => AttachmentsString = string.Join(",", value);
}
}
then in your controllers or service just manipulate with Attachments property.
I have two models :
public class CardPayment
{
[Required]
public Card CardDetail { get; set; }
[Required]
[MaxLength(100)]
public string Description { get; set; }
}
public class Card
{
[Required]
[MaxLength(50)]
public string CardHolder { get; set; }
[Required, MaxLength(3)]
public string Cv2 { get; set; }
}
I am validating the models with the following bit of code
var context = new ValidationContext(cardPayment);
var results = new List<System.ComponentModel.DataAnnotations.ValidationResult>();
if (Validator.TryValidateObject(cardPayment, context, results, true))
{
}
If i pass in a model with a description that has 101+ characters the validation works and the results collection has the validation error.
If i pass in the same model but set the Cv2 field to be 4+ characters it does not get picked up.
Is it possible for the TryValidateObject to validate the inner model?
I'm using Entity Framework Core, and the generated class has its own properties, i.e.
DataModel.Agent.cs
public partial class Agent {
public virtual decimal Id
{
get;
set;
}
public virtual string Name
{
get;
set;
}
}
But I need other properties, so I declare them in another file:
Agent.cs
public partial class Agent
{
[NotMapped]
public dynamic Custom { get; set; }
}
The problem is that Agent.cs is compiled before DataModel.Agent.cs, so the compiler generates properties in this order: Custom, Id, Name, and the resulting JSON is weird.
I want it to be: Id, Name, Custom. In other words, I always want the DataModel class to come first.
EDIT: Just to clarify, the only objective is to make the JSON prettier by always putting the Id first, which is a very common pattern. This has absolutely no impact on how the application works.
Is there a way to force the compiler to always compile one of the files first?
Well you really shouldn't count on JSON property order BUT if using json.net
public class Account
{
public string EmailAddress { get; set; }
// appear last
[JsonProperty(Order = 1)]
public bool Deleted { get; set; }
[JsonProperty(Order = 2)]
public DateTime DeletedDate { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime UpdatedDate { get; set; }
// appear first
[JsonProperty(Order = -2)]
public string FullName { get; set; }
}
http://www.newtonsoft.com/json/help/html/JsonPropertyOrder.htm
I was searching for this issues but haven't found what I need. I need to use Entity Framework model in Web API for getting XML requests and responses.
I have two classes with a one-to-many relationship:
[Serializable]
[DataContract(Name = "shepherd")]
[KnownTypeAttribute(typeof(Sheep))]
public partial class Shepherd
{
public Shepherd()
{
this.Sheep = new HashSet<Sheep>();
}
[DataMember(Name = "shepherdId")]
//[XmlElement("shepherdId")]
public int Id { get; set; }
[DataMember(Name = "name")]
//[XmlElement("name")]
public string Name { get; set; }
[DataMember(Name = "isDeleted")]
//[XmlElement("IsDeleted")]
public Nullable<bool> IsDeleted { get; set; }
[DataMember(Name = "sheeps")]
//[XmlArray("sheeps"), XmlArrayItem("sheep")]
public virtual ICollection<Sheep> Sheep { get; set; }
}
and this is the second class:
[DataContract(Name = "sheep")]
[KnownType(typeof(Shepherd))]
public partial class Sheep
{
[DataMember(Name = "id")]
//[XmlElement("id")]
public int Id { get; set; }
[DataMember(Name = "colour")]
// [XmlElement("colour")]
public string Colour { get; set; }
[DataMember(Name = "createdon")]
//[XmlElement("CreatedOn")]
public Nullable<System.DateTime> CreatedOn { get; set; }
public int Shepherd { get; set; }
[IgnoreDataMember]
public virtual Shepherd Shepherd1 { get; set; }
}
and I always get this error:
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
System.InvalidOperationException
Type 'System.Data.Entity.DynamicProxies.Shepherd_EF797FA5FAF7ACF0AF313B6DFF83AF6E5F2EE1AD57BC457F9C10E73BA5DEEFE6' with data contract name 'Shepherd_EF797FA5FAF7ACF0AF313B6DFF83AF6E5F2EE1AD57BC457F9C10E73BA5DEEFE6:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
I need to get only XML not Json
I'm trying to cast an IEnumerable of an inherited type to IEnumerable of base class.
Have tried following:
var test = resultFromDb.Cast<BookedResource>();
return test.ToList();
But getting error:
You cannot convert these types. Linq to Entities only supports conversion primitive EDM-types.
The classes involved look like this:
public partial class HistoryBookedResource : BookedResource
{
}
public partial class HistoryBookedResource
{
public int ResourceId { get; set; }
public string DateFrom { get; set; }
public string TimeFrom { get; set; }
public string TimeTo { get; set; }
}
public partial class BookedResource
{
public int ResourceId { get; set; }
public string DateFrom { get; set; }
public string TimeFrom { get; set; }
public string TimeTo { get; set; }
}
[MetadataType(typeof(BookedResourceMetaData))]
public partial class BookedResource
{
}
public class BookedResourceMetaData
{
[Required(ErrorMessage = "Resource id is Required")]
[Range(0, int.MaxValue, ErrorMessage = "Resource id is must be an number")]
public object ResourceId { get; set; }
[Required(ErrorMessage = "Date is Required")]
public object DateFrom { get; set; }
[Required(ErrorMessage = "Time From is Required")]
public object TimeFrom { get; set; }
[Required(ErrorMessage = "Time to is Required")]
public object TimeTo { get; set; }
}
The problem I'm trying to solve is to get records from table HistoryBookedResource and have the result in an IEnumerable<BookedResource> using Entity Framework and LINQ.
UPDATE:
When using the following the cast seams to work but when trying to loop with a foreach the data is lost.
resultFromDb.ToList() as IEnumerable<BookedResource>;
UPDATE 2:
Im using entity frameworks generated model, model (edmx) is created from database, edmx include classes that reprecent the database tables.
In database i have a history table for old BookedResource and it can happen that the user want to look at these and to get the old data from the database entity framework uses classes with the same name as the tables to receive data from db. So i receive the data from table HistoryBookedResource in HistoryBookedResource class.
Because entity framework generate the partial classes with the properties i dont know if i can make them virtual and override.
Any suggestions will be greatly appreciated.
Typically you use AsEnumerable<T> in such cases:
var test = resultFromDb.AsEnumerable().Cast<BookedResource>();
This has the advantage of not enumerating the whole result at once (you don't loose the laziness).
try with:
resultFromDb.AsEnumerable().Cast<BookedResource>();