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?
Related
Assuming I wan't to use single class to create and update an object in REST API - how I can do this without code duplication?
Create an object (POST) - all fields should be [Required].
Update an object (PATCH) - I want to use same class but fields should not be required as it can be done partially.
I can use below class for POST but can't for PATCH - as only Name may be updated (provided along the request) - which is OK.
public class Person
{
[Required]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
The only solution I see (that causes code duplication) is:
public class CreatePerson
{
[Required]
public string Name { get; set; }
[Required]
public string LastName { get; set; }
}
public class UpdatePerson
{
public string Name { get; set; }
public string LastName { get; set; }
}
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.
In my MVC application, I defined the DataAnnotations in the domain models. Although the DataAnnotations properties as Display, etc. can be retrieved when using Domain model, they cannot be retrieved when using the same properties on ViewModel and using this ViewModel. I think it is not seem to good to define the DataAnnotations in ViewModel again. So, is it possible or which way should I follow?
Domain Model:
public class Issue
{
[Key]
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Project Number")]
public int ProjectID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Issue Definition")]
public string Description { get; set; }
//... removed for brevity
//Navigation Properties:
public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}
ViewModel:
public class IssueViewModel
{
public int ID { get; set; }
public int ProjectID { get; set; }
public string Description { get; set; }
//... removed for brevity
//Navigation Properties:
public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}
You can create a new buddy class which holds all metadata about properties and class.
public partial class IssueMetadata
{
[Required(ErrorMessage = "Required")]
[Display(Name = "Project Number")]
public int ProjectID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Issue Definition")]
public string Description { get; set; }
}
Then, we must tell the MVC Framework about the buddy class through the MetadataType attribute, which takes the type of the buddy class as its argument. Buddy classes must be defined in the same namespace and
must also be partial classes.
[MetadataType(typeof(IssueMetadata))]
public partial class IssueViewModel
{
//...
public int ProjectID { get; set; }
public string Description { get; set; }
//...
}
[MetadataType(typeof(IssueMetadata))]
public partial class Issue
{
[Key]
public int ID { get; set; }
public int ProjectID { get; set; }
public string Description { get; set; }
//... removed for brevity
//Navigation Properties:
public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}
Additional note:
If IssueMetadata and Issue (or IssueViewModel) classes located in different assemblies, then you can associate classes with their buddy class in runtime, like that:
public class AssociatedMetadataConfig
{
public static void RegisterMetadatas()
{
RegisterPairOfTypes(typeof(Issue), typeof(IssueMetadata));
RegisterPairOfTypes(typeof(IssueViewModel), typeof(IssueMetadata));
}
private static void RegisterPairOfTypes(Type mainType, Type buddyType)
{
AssociatedMetadataTypeTypeDescriptionProvider typeDescriptionProvider
= new AssociatedMetadataTypeTypeDescriptionProvider(mainType, buddyType);
TypeDescriptor.AddProviderTransparent(typeDescriptionProvider, mainType);
}
}
And, just call this static method in global.asax:
AssociatedMetadataConfig.RegisterMetadatas();
#StephenMuecke is right. DomainModel attributes and ViewModel attributes are different and you can use them seperately in your models. But I would use inheretence in this case, if I were you. You can create a Partial class for ViewModel and inherit your DomainModel from this ViewModel class.
Like:
public class IssueVM
{
[Key]
public int ID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Project Number")]
public int ProjectID { get; set; }
[Required(ErrorMessage = "Required")]
[Display(Name = "Issue Definition")]
public string Description { get; set; }
//... removed for brevity
//Navigation Properties:
public virtual ICollection<FileAttachment> FileAttachments { get; set; }
}
public class IssueDM : IssueVM
{
// Other Fields
}
That way you have a base class of ViewModel (less fields) and a larger class with more fields for DB operations. Your ViewModel data annotation attributes are also inherited in your DomainClass that way.
I don't claim that this is the best way, but I'am using this and works fine.
I try to write a Blog with MVC4 and have problems with the Post - Comment (1 to n), as well as with the Post - Tag (n to m) relationship, using code first.
Tag:
public class Tag
{
[Key]
[Required]
public int ID { get; set; }
[Required]
public string Name { get; set; }
public IList<Post> Posts { get; set; }
}
Comment:
public class Comment
{
[Key]
[Required]
public int ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
[Required]
public DateTime DateTime { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Body { get; set; }
}
Post:
public class Post
{
[Key]
[Required]
public int ID { get; set; }
[Required]
public string Title { get; set; }
[Required]
public DateTime DateTime { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Body { get; set; }
public IList<Tag> Tags { get; set; }
public IList<Comment> Comments { get; set; }
}
Using this code first, I get a database which looks like:
Comment n to 1 Post n to m Tag
Where for the n to 1 the foreign key to Post is in Comment and for the n to m a Cross Table was created.
Now, I created a Controller as well as a View to create a new Post with Tags.
When I look into my database, everything is filled correctly. The Post and Tags exist, and the Cross Table is filled with the IDs.
But now, when I want to render the Post in my View I want to get the data with #post.Tags, where #post represents my currently selected Post which has the correct Data (Title, Name etc), but for Tags, which is the IList<Tag> from my Model I get a NullPointer Exception. (The same goes for #post.Comments)
Although, when creating the Post:
new Post() { ID = -1, Tags=new List<Tag>(), Comments=new List<Comment>(), DateTime = DateTime.Now };
Edit:
When using virtual, I get a System.Data.EntityCommandExecutionException. There is already an open DataReader associated with this Command which must be closed first
Solution
I was missing the virtual Keyword as well as to invoke the Include Method. To get the Method I had to use System.Data.Entity
Now it works, thank you both
You probably need to make the Tags and Comments properties of your Post class virtual so they can be lazy-loaded.
public virtual IList<Tag> Tags { get; set; }
public virtual IList<Comment> Comments { get; set; }
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>();