I am working with entity-framework. I have a partial class called Company that is generated by EF. The partial class looks like:
The type 'BaseModels.Company' already contains a definition for 'CompanyName'"
public partial class Company {
public string CompanyId { get; set; }
public string CompanyName { get; set; }
}
What I want to do is create a derived class from Company that has an extra property.
public class MyCompany : Company {
public string UploadName { get; set; }
}
But I want to decorate the base type property CompanyName with a custom attribute.
I went to the following location:
How do I add an attribute to the field of the base class from child class?
Which does answer my question. The problem is if I marked the CompanyName property in the base class as "virtual", then EF could regenerate the code which would override my stuff.
I tried to define a partial class, but VS 2013 complained when I tried to add:
public partial class Company {
[Renderer("html")]
public virtual string CompanyName { get; set; }
}
by stating that the property name already existed.
How would I get around this hurdle?
You cannot with partial class define property that already exists. You add attribute over existing property you need to use MetadataTypeAttribute. Create partial class:
[MetadataType(typeof(CompanyMetadata))]
public partial class Company { }
and add metadata class to your project with your property with desired attribute:
public class CompanyMetadata
{
[Renderer("html")]
public string CompanyName { get; set; }
}
Make Company an abstract class. Then use override keyword with CompanyName to add the custom attribute. You can also add UploadName.
Related
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.
I have set up my EF code-first database but want to add additional derived properties. (Yes, it should be in a view model, we can discuss another time why it is this way.) I have created a partial class extending the actual table class. If I add a [NotMapped] to the new partial, will it avoid mapping the additional properties I add there or will it apply to the entire class?
It will apply to the entire class. Remember that a partial class is simply a way of splitting a class into multiple files. From the official docs:
At compile time, attributes of partial-type definitions are merged.
So this:
[SomeAttribute]
partial class PartialEntity
{
public string Title { get; set; }
}
[AnotherAttribute]
partial class PartialEntity
{
public string Name { get; set; }
}
Is equivalent to writing:
[SomeAttribute]
[AnotherAttribute]
partial class PartialEntity
{
public string Title { get; set; }
public string Name { get; set; }
}
If you want to add a partial class without having the properties included in the model, you will need to add the NotMapped attribute to the individual items:
partial class PartialEntity
{
public string Title { get; set; }
}
partial class PartialEntity
{
[NotMapped]
public string Name { get; set; }
}
I have the follow class generated by Entity Framework
public partial class Album
{
public int AlbumID { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
}
I also have the following in another class
public class Album
{
public int AlbumID { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
}
I would like to know why Visual Studio is giving me an error about ambiguity and an already existing definition when the generated class is a partial class. I've tried making the non-partial class partial but it still gave me an error.
Error: Missing partial modifier on declaration of type 'Album'; another partial declaration of this type exists
A "Partial" class is just a way to break code in one class up between files. You may do this for ease of use, or even for code generation, but that's all it really does.
ALL class definitions with that name in that namespace for that class need to be tagged as "partial" for it to work.
Your second class "breaks" the partial functionality because it isn't marked as partial, but exists with the same name in the same namespace. You've also got duplicate definitions of properties, which will cause your NEXT error once you fix this one.
Which brings up the obvious question? Why do you believe you need two classes doing the same thing in the same namespace?
I have refactored an application which uses EF5 Database First. The application uses metadata classes to add data annotations to the entity properties. Before the refactor, these worked. They are mostly just display names and data formats.
Example:
[MetadataType(typeof(QueryDetailsResultMetadata))]
public partial class QueryDetailsResult : IPortfolio
{
public string Source { get { return "Local"; } }
}
public class QueryDetailsResultMetadata
{
//Fields from QueryDetailsResult requiring annotations
[Display(Name = "Company Name")]
public string SiteName { get; set; }
[Display(Name = "Contact Telephone Number")]
public string ContactTelNo { get; set; }
}
Before the refactor, the partial class did not inherit from an interface and it did not have the non mapped property. These changes are however required. Neither of these two should be causing a problem as both are well documented as valid solutions.
The interface looks like this
public interface IPortfolio
{
int Id { get; set; }
string SiteName { get; set; }
string YearOfManufacture { get; set; }
string Contact { get; set; }
string ContactTelNo { get; set; }
string Source { get;}
}
The display uses the properties like this
#Html.DisplayNameFor(model => model.Portfolio.ContactTelNo)
On the View at runtime, the property names are shown rather than the display names. Any ideas why? I can't see any reason for the annotations to be broken
//edit
I tried moving the annotations on to the new non-mapped fields in the partial and removed them from the metadata class. To seee if it had any effect. None. Also double checked the edmx is in the same Namespace as the partial class and metadata file which it is.
Any thoughts on what to check or try? Not having much success this end, most google results are just saying to use a metadata class which is already in place.
//2nd Edit
Moving annotations out of metadata class and on to the interface did the trick.
It is a little bit confusing how the DataAnnotation attributes are wroking with interfaces because:
at one hand classes don't inherit attributes from their interfaces: Is it possible to use DataAnnotations with Interfaces?
the the other hand you can/need put the attributes on the interfaces: ASP.NET MVC DisplayAttribute and interfaces
But how it works only depends on the type of your "container" in the view so lets consider the following types:
public class QueryDetailsResult : IPortfolio
{
public string SiteName { get; set; }
}
public interface IPortfolio
{
string SiteName { get; set; }
}
So if you have #Html.DisplayNameFor(model => model.Portfolio.SiteName) in your view
and your model class looks like
public class Model {
public QueryDetailsResult Portfolio { get; set; }
}
then you need to put the DisplayAttribute on the SiteName property of your QueryDetailsResult class because MVC looks for the "container" type in the model.Portfolio.SiteName expression which is QueryDetailsResult
but if you have your model class defined as
public class Model {
public IPortfolio Portfolio { get; set; }
}
then you need to put it on the SiteName property of the IPortfolio interface because your "container" type is the IPortfolio interface.
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.