I have the following entities for example:
public class BaseClass
{
[Required]
public virtual string DisplayName { get; set; }
}
public class FirstChildClass: BaseClass
{
public int Id { get; set; }
}
public class SecondChildClas: BaseClass
{
public int Id { get; set; }
}
Then i have the following viewmodel:
public class MyViewModel
{
public FirstChildClass FirstProperty { get; set; }
public SecondChildClass SecondProperty { get; set; }
}
In my View i have a form which submits the following properties FirstChildClass.Id and SecondChildClass.Id.
My problem is that the inherited DisplayName is added to my ModelState due to the [Required] attribute. I'd like to ignore the validation of inherited properties without removing them explicitly from the ModelState with Remove().
Is there any way to accomplish it?
I would suggest not using inheritance here. What is BaseClass:
I have DisplayName and it should be Required but not always, it depends, looks in all derived classes to understand how I work.
If you really want to go that way check if you can make this property virtual, and add attribute only to one derived class.
Related
I have a base class like this-ish:
public class Baseclass
{
public string Id { get; set; }
public string Type { get; set; }
public string Name { get; set; }
}
...and many classes that inherit these properties, like this-ish:
public class Thing: Baseclass
{
public string Size{ get; set; }
public string Color{ get; set; }
public string Smell{ get; set; }
}
Now, I don't want to serialize all of these properties (mvc/jsonresult), so I use [JsonIgnore] on the properties of a class I want to exclude, and that works fine. The problem is that I don't want to serialize all the inherited properties for a class either. I've asked around and gotten the following answer:
Ex: I don't want to serialize the inherited Id from Baseclass in Thing.
I should make Id in Baseclass virutal:
public virtual string Id { get; set; }
and add the following to the Thing class:
[JsonIgnore]
public override string Id { get; set; }
...but this doesn't work, I'm afraid. I can get around it rebuilding the class hierarchy. but I would prefer a simpler solution. Any suggestions as to why this solution didn't work or alternatives to exclude certain inherited properties?
Suppose I have 2 entities one is UserMaster another is ProjectMaster, now there are few common properties in both the entities and I need to apply same data annotations and attributes on both set of common properties which I do using metadata classes, now my question is there any way that I have a common metadata class for all this common properties across entities,so that I don't need apply data annotation and attributes for common properties again and again and if yes then how to achieve this.
You can create a base metadata class and the other metadata class derive from the base and add some other properties.
Example:
In the below example I supposed you can't derive Class2 from Class1 so I have inheritance only between metadata classes, otherwise you can simply have inheritance between your model classes.
[MetadataType(typeof(Class1Metadata))]
public class Class1
{
public string Id { get; set; }
public string Name { get; set; }
}
[MetadataType(typeof(Class2Metadata))]
public class Class2
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
public class Class1Metadata
{
[Display(Name="Id1")]
public string Id { get; set; }
[Display(Name = "Name1")]
public string Name { get; set; }
}
public class Class2Metadata:Class1Metadata
{
[Display(Name = "Description2")]
public string Description { get; set; }
}
I have two related entities called DataTag and TagSource that look like the following:
public class DataTag : BaseModel
{
[Column("DataTagId")]
public override Guid ID { get; set; }
public string Tag { get; set; }
public Guid TagSourceId { get; set; }
public TagSource TagSource { get; set; }
}
public class TagSource : BaseModel
{
[Column("TagSourceId")]
public override Guid ID { get; set; }
public string Description { get; set; }
public bool IsInternal { get; set; }
public string Source { get; set; }
public ICollection<DataTag> DataTags { get; set; }
}
I am allowing the user to Include the navigation properties through the url like "/api/DataTags?Include=TagSource". The problem is when I include the TagSource, it also includes the collection of DataTags in that object which I don't want unless the user specifies it (For example "/api/DataTags?Include=TagSource.DataTags". Is there any way to stop that property from being loaded when I include the TagSource? I have tried making the properties virtual and turning lazy loading off globally but that didn't work. The reason I haven't marked them virtual is because I am using AutoMapper and I only want to include the navigation properties that the user specifies.
As in the comments you need to create a DTO object. There is a good article here detailing how to do this with WebAPI
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-5
Edit.
The problem with this is you will need a lot of different DTO objects for each possible outcome which could become messy. If your return type is JSON you can add this attribute to your properties:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Firstly : Apologies for my English.
Secondly : I had the same issue with a code first database model that creates foreign keys this way : public virtual Collection<Object> Objects {get; set;}
and I found a workaround by setting the property setter as private:
public virtual Collection<Object> Objects {get; private set;}
Then the EF cannot populate the Objects collection because with a private set you can only assign a value in constructors.
I'm using Entity Framework 5 in Database First approach and I am using edmx file.
Most of my entities have 6 common fields. Fields like CreatedAt, CreatedBy etc. Now, I implemented some functions as extensions that can only be applied to IQueryable of those Entities that have the common fields. But when I implement the extension method, it can be accessed by any type of IQueryable as it's typed T and I can only define that the type T should always be of one type.
So, I thought I can give a base class to the entities which has common fields and define type T as that base type. But, it seems I can't do this.
Any idea on how to solve this or implement what I have explained above?
Don't create a base class. Create an Interface, like below:
public interface IMyEntity
{
DateTime CreatedAt { get; set; }
string CreatedBy { get; set; }
// Other properties shared by your entities...
}
Then, your Models will be like this:
[MetadataType(typeof(MyModelMetadata))]
public partial class MyModel : IMyEntity
{
[Bind()]
public class MyModelMetadata
{
[Required]
public object MyProperty { get; set; }
[Required]
public string CreatedBy { get; set; }
}
}
I'm a fan of:
public interface IShared
{
DateTime CreatedOn { get; set; }
}
public interface ISharedValidation
{
[Required]
DateTime CreatedOn { get; set; }
}
public interface IMyEntity: IShared
{
// Entity Specifics
string Username { get; set; }
}
public interface IMyEntityValidation: ISharedValidation
{
[Required]
string Username { get; set; }
}
Then, your Models will be like this:
[MetadataType(typeof(IMyEntityValidation))]
public partial class MyModel : IMyEntity
{
public object CreatedOn { get; set; }
public string Username { get; set; }
}
If T4 generated by Entity Framework then your non-autogenerated class would look like:
[MetadataType(typeof(IMyEntityValidation))]
public partial class MyModel : IMyEntity
{
}
Typically, it is not recommended to use Bind in Asp.Net MVC.
Given the class:
public class Item
{
[Key]
public int ID { get; set; }
[Display]
public string Name { get; set; }
public string Observation { get; set; }
public DateTime? Done { get; set; }
}
I know i can define my [Key] Attribute and other mapping settings by create a mapping class in another project and inheriting from EntityTypeConfiguration.
but how can i replace the [display] attribute so i don't have to add a reference to System.ComponentModel.DataAnnotations to my common dll?
tell me if i'm not clear enough
You can create your own attribute, then write a class that inherits AssociatedMetadataProvider and reads data from your attribute into a ModelMetadata instance.
Your class would be similar or identical to the built-in version.