views:

3570

answers:

4

I have implemented some table-per-type inheritance in my data model (basically have a "BaseEntity" type with all the base information for my items and a "Employer" type that inherits from the "BaseEntity" item). Everything appears to be set up correctly and when using the Entities (either via ADO.net Data Services or via Linq to Entities) I can see the Employer type and things appear to be fine. The issue starts when I create a new Employer entity and attempt to save it.

On the context that doesn't appear to be an .AddToEmployer item (only and AddObject or AddToBaseEntity). If I use AddObject("Employer", NewEmployer) I get and error message of: "The EntitySet name 'DataEntities.Employer' could not be found." If I use AddToBaseEntity(NewEmployer) I get an error message of: "Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements orstore generated values."

Have I missed a step in setting up the inheritance? Is there some specific way to save objects that are inherited? What am I doing wrong? I assume that the basic issue is that I should have an AddToEmployer, what do I need to do to get that exposed. It seems odd that it is not an option since I can see the Employer type on the client side and can do things such as "var NewEmployer = new Employer()" - which seems to suggest that I can see the Employer type fine.

A: 

You don't have Employer defined as entity set, just like entity type. That is way you are missing AddToEntity in the context object. There is always one entity set for one class hierarchy, in this case it is BaseClass entity set.

If you want to get entity set 'Employer' you can try to manually edit edmx file and to add new entity set 'Employer', and then set entity type 'Employer' to belong to that entity set. It shouldn't be hard, I've done it a lot of times.

I'm not sure if there is some more regular solution.

Nenad
+2  A: 

Well you only get an entity set pr. base class so .AddToBaseEntity is the solution as such.

But it sounds like you have a circular dependency in your model, so that the Entity framework cannot figure out in which order to save.

Check that you have foreign keys to the baseentity on your derived entities and update your model.

Luhmann
+1  A: 

I changed a couple of things and was able to get this to work. I am not particularly sure what was the base issue, but wanted to post what I did do for reference.

Rebuilt Tables: I rebuilt the tables starting with just the ID/Key columns and a single data column.

Removed extra auto incrementing fields: I had an auto-incrementing ID on the BaseEntity and on the Employer. I removed the auto-incrementing ID on the Employer and just had the Employer.BaseEntityID column and the foreign key back to BaseEntity.BaseEntityID. (this seems to have been the culprit, but I was under the impression this was permitted)

Unfortunately this then lead to the issue that enherited classes in the entity framework cannot have navigation properties (all navigation properties must be on the base entity) so inheritance is going to prove to be non-usable for our needs.

ChrisHDog
+4  A: 

Hi , My Name is Phani and I work on the ADO.NET Data Services team.

The ResolveName and ResolveType methods are to help you customize the type information that the client writes in the payload sent to the server and how the response payload from the server is materialized .

They help you resolve types on the client and are useful in many scenarios , a couple of examples are :

  1. The type hierarchy of entities are on the client different compared to the server.
  2. Entity Types exposed by the service participate in inheritance and you want to work with derived types on the client.

ResolveName is used to change the name of the entity that we put on the wire when making a request to the server.

Consider this data model : On Server

public class Employee {
    public int EmployeeID {get;set;}
    public string EmployeeName {get;set;}
}

public class Manager:Employee {
    public List<int> employeesWhoReportToMe {get;set;}
}

When you use the client to work with instances of the Manager Entity Type , upon submitting the changes to the server, we expect type information to be present in the payload when entities participate in inheritance.

context.AddObject("Employees",ManagerInstance ); <-- add manager instance to the employees set.
context.SaveChanges();

However, when the client serializes this payload, it puts in "Employee" as the type name which is not what is expected on the server. Hence you have to provide a name resolver on the client,

context.ResolveName = delegate(Type entityType){
    //do what you have to do to resolve the type to the right type of the entity on the server
    return entityType.FullName;
}

a Type resolver is used in the same way .

context.ResolveType = delegate(string entitySetName){
    //do what you have to do to convert the entitysetName to a type that the client understands
    return Type.GetType(entitySetName);
}
Phani Raj