I have an abstract class and other classes that inherit from it.
Those classes are below:
[Table("Contents", Schema="Admon")]
public abstract class Content
{
public Content()
{
this.EntryDate = DateTime.Now;
}
[Key]
public int ID { get; set; }
public string Title { get; set; }
public int? ParentID { get; set; }
[StringLength(15)]
public string InfoType { get; set; }
public DateTime EntryDate { get; set; }
public string Preview { get; set; }
public string Description { get; set; }
public string Link { get; set; }
public string Text { get; set; }
public string CategoryID { get; set; }
public int? DocID { get; set; }
public virtual Content Parent { get; set; }
public virtual ICollection<Content> Subs { get; set; }
}
public class Photo : Content { }
public class Notice : Content { }
public class Article : Content { }
public class Calendar : Content { }
My problem is that anytime i run my app it throws an exception that reads
System.MissingMethodException: Cannot create an abstract class
What can I do to rectify this error.
Thanks in advance
To use inheritance in Entity Framework, you have to implement TPH (Table per Hierarchy) or TPT (Table per Type) database structure.
With this strategy, you will be able to implement your expected behavior.
You can follow this article to implement TPH or TPT, and learn about this technology.
Hope it helps !
You cannot create an instance of an abstract class. An abstract class contains abstract members which define what a subclass should contain.
If this class must remain abstract you need to create a second class that inherits from it and implements it's members and use that class to do your processing with.
If the class doesn't have to remain abstract (I can't see why it should be but without seeing the rest of your code I can't be 100% sure) then just remove the abstract keyword.
The class Content would not compile because the your class is abstract. The MVC engine
cannot create an instance of Content directly.Unless you give it some way to know which type of Problem to instantiate, there's nothing it can do.
It is possible to create your own ModelBinder implementation, and tell MVC to use it. Your implementation could be tied to a Dependency Injection framework, for example, so that it knows to create a Content1 whenever a Content class is requested.
Related
Using EF Code First and given an Entity that contains a List, how can I eagerly load the entire object graph for that entity:
Example:
public class Foo
{
public int Id { get; set; }
public List<BarBase> Bars { get; set; }
}
public class BarBase
{
public int Id { get; set; }
public string Text { get; set; }
}
public class BarTypeA : BarBase
{
public List<Baz> Bazes { get; set; }
}
public class BarTypeB : BarBase
{
public List<Quux> Quuces { get; set; } { get; set; }
}
If BarBase were not a base class that could contain instances of several different subtypes, I could use
.Include("Bars").Include("Bars.Bazes")
If I try
.Include("BarBase").Include("BarBase.Bazes").Include("BarBase.Quuces")
I get the error
A specified Include path is not valid. The EntityType 'BarBase' does
not declare a navigation property with the name 'Bazes'.
But how do I handle the situation that Bars can contain different concrete types, and I want to eagerly load all of those instances including the List<T> contained in those concrete types?
This is reported problem in EF currently without a solution.
I'm guessing this is impossible, but I'll throw it out there anyway. Is it possible to use CreateSourceQuery when programming with the EF4 CodeFirst API, in CTP4? I'd like to eagerly load properties attached to a collection of properties, like this:
var sourceQuery = this.CurrentInvoice.PropertyInvoices.CreateSourceQuery();
sourceQuery.Include("Property").ToList();
But of course CreateSourceQuery is defined on EntityCollection<T>, whereas CodeFirst uses plain old ICollection (obviously). Is there some way to convert?
I've gotten the below to work, but it's not quite what I'm looking for. Anyone know how to go from what's below to what's above (code below is from a class that inherits DbContext)?
ObjectSet<Person> OSPeople = base.ObjectContext.CreateObjectSet<Person>();
OSPeople.Include(Pinner => Pinner.Books).ToList();
Thanks!
EDIT: here's my version of the solution posted by zeeshanhirani - who's book by the way is amazing!
dynamic result;
if (invoice.PropertyInvoices is EntityCollection<PropertyInvoice>)
result = (invoices.PropertyInvoices as EntityCollection<PropertyInvoice>).CreateSourceQuery().Yadda.Yadda.Yadda
else
//must be a unit test!
result = invoices.PropertyInvoices;
return result.ToList();
EDIT2:
Ok, I just realized that you can't dispatch extension methods whilst using dynamic. So I guess we're not quite as dynamic as Ruby, but the example above is easily modifiable to comport with this restriction
EDIT3:
As mentioned in zeeshanhirani's blog post, this only works if (and only if) you have change-enabled proxies, which will get created if all of your properties are declared virtual. Here's another version of what the method might look like to use CreateSourceQuery with POCOs
public class Person {
public virtual int ID { get; set; }
public virtual string FName { get; set; }
public virtual string LName { get; set; }
public virtual double Weight { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class Book {
public virtual int ID { get; set; }
public virtual string Title { get; set; }
public virtual int Pages { get; set; }
public virtual int OwnerID { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual Person Owner { get; set; }
}
public class Genre {
public virtual int ID { get; set; }
public virtual string Name { get; set; }
public virtual Genre ParentGenre { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
public class BookContext : DbContext {
public void PrimeBooksCollectionToIncludeGenres(Person P) {
if (P.Books is EntityCollection<Book>)
(P.Books as EntityCollection<Book>).CreateSourceQuery().Include(b => b.Genres).ToList();
}
It is possible to add a method to you derived context that creates a source query for a given navigation on an entity instance. To do this you need to make use of the underlying ObjectContext which includes a relationship manager which exposes underlying entity collections/references for each navigation:
public ObjectQuery<T> CreateNavigationSourceQuery<T>(object entity, string navigationProperty)
{
var ose = this.ObjectContext.ObjectStateManager.GetObjectStateEntry(entity);
var rm = this.ObjectContext.ObjectStateManager.GetRelationshipManager(entity);
var entityType = (EntityType)ose.EntitySet.ElementType;
var navigation = entityType.NavigationProperties[navigationProperty];
var relatedEnd = rm.GetRelatedEnd(navigation.RelationshipType.FullName, navigation.ToEndMember.Name);
return ((dynamic)relatedEnd).CreateSourceQuery();
}
You could get fancy and accept a Func for the navigation property to avoid having to specify the T, but here is how the above function is used:
using (var ctx = new ProductCatalog())
{
var food = ctx.Categories.Find("FOOD");
var foodsCount = ctx.CreateNavigationSourceQuery<Product>(food, "Products").Count();
}
Hope this helps!
~Rowan
It is definately possible to do so. If you have marked you collection property with virtual keyword, then at runtime, you actual concrete type for ICollection would be EntityCollection which supports CreateSourceQuery and all the goodies that comes with the default code generator. Here is how i would do it.
public class Invoice
{
public virtual ICollection PropertyInvoices{get;set}
}
dynamic invoice = this.Invoice;
dynamic invoice = invoice.PropertyInvoices.CreateSourceQuery().Include("Property");
I wrote a blog post on something similar. Just be aware that it is not a good practice to rely on the inner implementation of ICollection getting converted to EntityCollection.
below is the blog post you might find useful
http://weblogs.asp.net/zeeshanhirani/archive/2010/03/24/registering-with-associationchanged-event-on-poco-with-change-tracking-proxy.aspx
i'd like to know, I have a application in asp.net mvc and nhibernate. I've read about that in the Views on asp.net mvc, shouldn't know about the Domain, and it need use a DTO object. So, I'm trying to do this, I found the AutoMapper component and I don't know the correct way to do my DTOS, for some domain objects. I have a domain class like this:
public class Entity
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
}
public class Category : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Category() { }
}
public class Product : Entity
{
public virtual string Name { get; set; }
public virtual string Details { get; set; }
public virtual decimal Prince { get; set; }
public virtual int Stock { get; set; }
public virtual Category Category { get; set; }
public virtual Supplier Supplier { get; set; }
public Product() { }
}
public class Supplier : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Supplier() { }
}
I'd like to get some example of how can I do my DTOs to View ? Need I use only strings in DTO ? And my controllers, it should get a domain object or a DTO and transform it on a domain to save in repository ?
Thanks a lot!
Cheers
There is no guidelines on this matter and it depends on your personal chice. I have few advices that have proven useful in practice:
1. Use flat DTOs - this means that the properties of the DTO must be as primitive as possible. This saves you the need for null reference checking.
For example if you have a domain object like this:
public class Employee
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop Employee Boss{get; set;}
...
}
And you need to output in a grid a list of employees and display information for their 1st level boss I prefer to create a DTO
public class EmployeeDTO
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop bool HaveABoss{get;set}
prop string BossFirstName{get; set;}
prop string BossLastName{get; set;}
...
}
or something like this (-:
2. Do not convert everything to sting - this will bind the DTO to a concrete view because you'll apply special formatting. It's not a problem to apply simple formatting directly in the view.
3. Use DTOs in your post actions and than convert them to domain objects. Usually controller's actions are the first line of deffence against incorrect data and you cannot expect to be able to allways construct a valid domain object out of the user's input. In most cases you have to do some post-processing like validation, setting default values and so on. After that you can create your DTOs.
So in my mvc project's Project.Repository I have
[MetadataType(typeof(FalalaMetadata))]
public partial class Falala
{
public string Name { get; set; }
public string Age { get; set; }
internal sealed class FalalaMetadata
{
[Required(ErrorMessage="Falala requires name.")]
public string Name { get; set; }
[Required(ErrorMessage = "Falala requires age.")]
public string Age { get; set; }
}
}
I use Falala as a model in my Project.Web.AccountControllers, and use a method to get violations.
Validating worked when I had
public class Falala
{
[Required]
public string Name { get; set; }
[Required(ErrorMessage="error")]
public string Age { get; set; }
}
but not after using the partial class from above.
I really need to use a partial class. What am I doing wrong here?
Thanks!
I tend to use Metadata classes as followed.
[MetadataType(typeof(FalalaMetadata))]
public partial class Falala
{
public string Name { get; set; }
public string Age { get; set; }
}
public class FalalaMetadata
{
[Required(ErrorMessage="Falala requires name.")]
public string Name { get; set; }
[Required(ErrorMessage = "Falala requires age.")]
public string Age { get; set; }
}
Which works fine for me.
The following should also work (and is a better way to implement metadata classes):
[MetadataTypeAttribute(typeof(Falala.FalalaMetaData))]
public partial class Falala
{
internal sealed class FalalaMetadata
{
[Required(ErrorMessage="Falala requires name.")]
public string Name { get; set; }
[Required(ErrorMessage = "Falala requires age.")]
public string Age { get; set; }
}
}
I ran into a similar problem and finally got it working by putting both the Model class and the Metadata "buddy" class in the same namespace, even though my references seemed ok. I'm kind of a .net noob though so I'm not exactly comfortable with namespaces, could be something else.
Could Internal on the nested class be the reason...?
I had a similiar problem and it seemed to all boiled down to not making the individual fields in the nested metadata class public - wonder if making the whole class internal causes the same problem?
Not sure if this help, but I had a similar problem and spend days on it. At the end it was just a minor change which did the trick for me.
I changed UnobtrusiveJavaScriptEnabled to false in the config file
Good luck
I know this works for single properties as per Scott Guthrie's blog to auto-magically use a partial view to render a partial model passed to it (UI Helper like in dynamic data):
[UIHint("StateDropDown")]
public string State { get; set;}
But how do you annotate an entire class to use an UI helper like this:
[UIHint("Address")]
public class Address {
public string addr1 { get; set; }
public string addr2 { get; set; }
public string city { get; set; }
[UIHint("StateDropDown")]
public string state { get; set; }
public string zip { get; set; }
}
(Except [UIHint("Address")] doesn't seem to work on classes. I see in his examples, he has "Customer.aspx" in the Shared->EditorTemplates folder, so I assume this is possible.
Make a template with the name of the class, and it just works.