Ask a questionAsk a question
 

AnswerDLinq Inheritance problem

  • Saturday, July 22, 2006 4:08 PMpolease Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I'm trying to use the DLinq to accomplish my business object hierachy, the target model is shown as following:

    public class Entity
    {....}

    public class User : Entity
    {...}

    public class Group : Entity
    {...}

    In the database , I have one table for each class, each table has a Guid, which has been used as the foriegn key. I designed a Enterprise.dlinq file, drag and drop all the tables to the designer and save it.

    After that I have done two examination:

    1. using the build-in inheritance tool, but I got the answer that it only support for one table with discrimitive column and value.

    2. using patial class to define the inheritance outside.
    I created another cs file, define as following:
    public partial class User : Entity
    {
    //empty class, just used to make the inheritance
    }  
    the compile is fine. When I run it and try to use linq setence to get data from database, it always throw exception for that piece of code. I believe it's due to the not -constructed base class reason.

     

    I have made a search for previous answer, I found the following one http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=396490&SiteID=1 which Jomo said we could use different tables to map to different classes. But as my experiment, it doesn't work.

    Any solution for this kind of problem?

    Thanks in advance.

     

     

Answers

  • Saturday, July 22, 2006 9:18 PMDinesh Kulkarni - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    As my team member Jomo has mentioned in the post, we support only the "table-per-hierarchy" (TPH) mapping. So the above mapping of inheritance hierarchy to different tables is not supported. In the post you cite, Jomo pointed out that you can have a common interface across two hierarchies - each in a different table. However, it is not mapped and DLinq cannot query for it. For V1, any polymorphic query must be against a single table.

    Thanks.
    Dinesh

All Replies

  • Saturday, July 22, 2006 9:18 PMDinesh Kulkarni - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer

    As my team member Jomo has mentioned in the post, we support only the "table-per-hierarchy" (TPH) mapping. So the above mapping of inheritance hierarchy to different tables is not supported. In the post you cite, Jomo pointed out that you can have a common interface across two hierarchies - each in a different table. However, it is not mapped and DLinq cannot query for it. For V1, any polymorphic query must be against a single table.

    Thanks.
    Dinesh

  • Saturday, September 02, 2006 9:16 AMGoodwill Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I dont know if my observation is correct- but I think thats not exactly about multiple table inheritance.

    Lets put my example here:

    public abstract class PersistentBase {

     public Guid ID;

    public PersistentBase (){

    ID=Guid.NewGuid();

    }

    }

    [Table]

    public class Customer:PersistentBase {

    [Column]

    public string CompanyName;

    }

    Note that this inheritance only results in 1 table- PersistentBase is never meant to be created. Its like a column templating function that we usually use to enforce couple standard columns in place. It would always appear in every table (e.g. Primary Key, user name for audit trail, etc.). I have tested this and exactly come across the problem the previous poster has came thru. I think this is a quite inconvenient issue.

     

  • Wednesday, August 29, 2007 3:46 PMdjnz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Any chance of this being fixed, or is this another example of "Good idea, shame that Microsoft can't do things properly"?  It would be very nice to have a *properly* functional ORM built in...
  • Friday, August 31, 2007 8:04 PMcverdon Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    For more complex inheritance, you can use the entity framework.

    Regards,
    Charles
  • Monday, October 08, 2007 10:07 PMkennykaz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    The entity framework offers a slightly solution for data access.  While it might solve some of the inheritance issues, it definitely favors a different style of coding.  Having read-only properties and the ability to control objects that I create as a developer is a HUGE benifit to me.  The entity framework seems to force the developer into creating an object that looks a lot like a dataset which can span multiple tables.  The aforementioned problem does not seem like it would be that hard to solve and certainly shouldn't necessitate the use of the entity framework. 

     

    It seems very likely that a system might have a base entity that always stores an id, a created date and a last updated date.  This data should exist on an abstract base class that doesn't represent a specific table.  A system would never need to load the abstract class but the Linq framework should be able to read the mappings from the base object.  For example, a concrete implementation of the base class could be a "Person" class with a "Name" property but would inherit it's id, created date, last updated date and subsequent mappings from it's base class.

     

    I have rolled my own datamapper that is very similar to Linq and it can handle private constructors as well as inheritance.  I'm very interested in Linq because I would no longer have to support my own mapping solution and because so many of the data access problems have been solved in a similar way.  Will Linq support this type of inheritance in the future?  What about private constructors?

  • Tuesday, October 09, 2007 1:06 AMDaniel Simmons - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Can you be more specific about what things in the entity framework lead you to the conclusion that it forces a very different coding style?  What aspects of control over your objects are you missing in the entity framework?  I don't want to argue you into any particular approach to solving your problems, but I do want to understand the issues you are facing so that we can make the best possible frameworks to support your needs. 

     

    It's my suspicion that your conclusion that the entity framework forces the developer into creating objects that look like a dataset may either be based on older versions of the entity framework (a lot has changed over the last year) or on a misunderstanding of how the entity framework works (it's quite possible that we have not done the job we should have in explaining these things).  Of course it's also possible that there are things that the entity framework doesn't do the way it should.  In any case, I'd like to better understand.

     

    Thanks in advance for your feedback,

    Danny

     

  • Tuesday, October 09, 2007 4:34 PMkennykaz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I could be wrong but my research into the entity framework leads me to believe the following:

     

    -  The framework favors / requires code generation.  There is a designer that generates both an xml file that describes the mapping and a "code behind" type file.  Although you might be able to modify the mapping file, there is a warning in the generated code that changing anything could lead to undesired results and could be overwritten. 

     

    -  The framework creates and requires objects with public empty constructors and public accessors for properties that are to be stored in the database.  Read-Only properties are not supported and a private field cannot be mapped to the database.

     

    -  The support for custom logic behind a "getter" or "setter" is awkward at best.  To implement any logic behind a "getter" or "setter" would require wiring up to an event handler.

     

    -  The framework does not support inheritance for methods or properties that do not map to the database.  For example, a base object called EntityBase is desired and would hold the property LastUpdatedDateTime which could automatically be set during a save operation for every concrete implementation of EntityBase.  Another example would be a Validate method that can be overridden or extended for each concrete implementation.  This is a way to eliminate multiple coding solutions for identical behavior throughout a system and is especially useful when all of the objects in the system have identical behavior.

     

    It is my preference to have business objects be responsible for themselves.  For example it would be my preference that an object is able to validate and save itself.  Although I would not consider this specific example a "hill worth dying on", I would prefer to encapsulate my code about a member within the member class and call member.Save() or member.Validate() rather than MemberDAC.Save(member) or MemberValidator.Validate(member).  As well, the desire for objects to be responsible for themselves means I put a premium on read only properties, constructors that take parameters and different levels of access to those constructors.  Another example would be a CreatedDateTime or LastUpdatedDateTime property.  I need to make sure that not just anyone or anything can change those fields.  I don't want another developer or me to purposely or accidently change either of those fields so I would make both properties read only and allow the object to make the appropriate decisions as to when those fields are updated. 

     

    To further explain some of my coding practices, I commonly find myself needing immutable objects which require a constructor with parameters making a public parameterless constructor pointless because it would always create an object in an improper state.  In addition, if I want an object to only be instantiated through a factory method, a private constructor would be a must.  Note that I think the requirement of a private parameterless constructor is acceptable as I know it would be required for instantiating an object in the data layer.

     

    I understand that all of these data mapper requirements are motivated by the way I prefer to code but I'm motivated by more than just preference.  I try not to make the UI my only means of controlling data.  I try to make sure that each object and each tier / assembly is as responsible for itself as possible and while I may have multiple interfaces (i.e. a website, a windows app and a webservice) there should be no way to circumvent the business logic.  My review of both Linq and the Entity Framework lead me to believe that I would need to wrap the objects I use for data access with objects that encapsulate my business logic if I want to meet the aforementioned goals. 

     

    Finally, code generation has never been a good solution for me.  I've used it a lot and it has always seemed to create more problems than it solves.  As well, code generation and inheritance never seem to play very nicely together.  I know I'm lacking specifics but the "to generate or not to generate" argument has been going on for a long time and seems to have no end in sight so there is really no need to encourage that debate.

     

    Linq seems like a better candidate for what I am trying to do but lacks support for the inheritance problem mentioned above.  As well, it also seems to require public parameterless constructors.  If just those two problems were solved in Linq, I would be ecstatic.  I hope I am wrong about the Entity Framework and I hope that there is a reasonable solution that will allow me to code with happiness.  I'm looking forward to your reply.

     

  • Tuesday, October 09, 2007 10:05 PMDaniel Simmons - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thanks for the extensive and thoughtful feedback.  Actually I believe a number of the things you are looking for are possible with the entity framework or will be possible in beta 3 (which will come out later this year).  There are some cases where we don't yet have the capabilities you are looking for or where things are not yet as easy as I would like them, but those are all things we are working on and plan to address in future releases.


    Let me see if I can address some of the specific comments:

     

    1) The entity framework most certianly does not require code generation.  There are facilities for code generation and some of the UI/designer surface is geared toward those scenarios because they work well in a number of situations, but it is also possible to author your own classes by hand, implement a few key interfaces and use the entity framework that way.  Your classes can but do not have to inherit from a common base class which is used in our generated classes.  That said, this is something which we intend to make much easier in future releases.  The long term goal is to support full persistence ignorance with the ability to opt-in to persistence awareness when/as needed.

    2) While the default generated classes have an automatically supplied public parameterless constructor, there's nothing in the framework that requires this to be so.  There must be a parameterless constructor, but it can be private.  You can try a simple example by taking the generated classes and just adding in a private parameterless constructor.  At that point the generated factory method will work to create instances for users, but the system will just use the private parameterless constructor to materialize objects that are the results of queries.  Another request which we have gotten is to support mapping directions so that even materialization of queries will go through factory methods, and that's something we will likely support in a future release but won't be supported in v1.  At any rate, though, I think your main request here will be supported.

     

    Also you said that hte system requires public settable properties for all fields that are persisted to the database, and again I'm happy to report that this isn't the case.  The default generated classes do create public properties for each persisted field, but you can either write your own class or modify the output of a generated class to make the property private.  Then you could create your own property with just a getter which retrieves its value from the private property.  The system doesn't currently allow you to attribute a field directly, and the designer doesn't support configuring this visually, but it is definitely possible to do.

    3) Support for adding business logic to the setters of the generated classes will be getting much easier in beta 3 since we are introducing partial methods for property changing and property changed.  We don't currently have a plan for partial methods for the getters, but again you can write your own classes rather than just using the generated classes.  One simple way to write your own classes is to let the system generate the classes for you once and then modify those and don't generate after that.  Or you can completely write your own classes (IPOCO is the information you want to look for in the documentation).

     

    4) Creating a Validate method that can be overridden for every concrete type in the system is also something that can be supported albeit, not 100% directly.  The two things you would need are 1) To create an abstract type in your model which all of your concrete types inherit from.  If the type is abstract, the system does not require you to have an entityset for it or even to map it.  You could just have concrete, mapped entitysets for the types which inherit from that type.  You could then put onto that type (in your class if you are writing from scratch or in your partial class if you are using the generated classes) an abstract Validate method which can be overridden in the various concrete classes as appropriate.  2) Create an event handler for the SavingChanges event on the context which goes through all of the inserted or updated entities and calls the Validate method.  In future releases we'll look into ways to make this even easier for generated classes using partial methods and other mechanisms, but it should be possible now.

     

    5) You also mentioned that you would prefer to have a Save method on entity classes themselves rather than a centralized Save.  This is something we considered but in the end rejected in favor of the broader "unit of work" pattern where you can make changes to a series of related objects and then save them all at once.  This is particularly useful when you are modifying relationships between entities or making changes to multiple entities that you want in a single transaction.  You could do manually transaction management either way, but the default transactions tha the entity framework supplies cover a large number of scenarios.  You could, of course, with some work maintain a reference from your entities back to the objectcontext they go with and add a Save method to the entities, but it would still save all the outstanding changes on the context so that would probably be confusing/error prone.  So this is an area were we don't directly support your request, but arguments can be made for either approach. 

     

    I suspect that there are other concerns which I have missed, but hopefully these ideas will help keep the thought processes and conversation flowing.  I appreciate the feedback you have given and respect the thoughtfulness you are putting into your architectures as you are building your applications.  The entity framework (or linq to sql) may not be a perfect fit right now for what you are trying to do, but with some creativity it can probably be a better fit than you think.  It's certainly our goal to deliver a system over the course of a few releases that will address all of these scenarios and more.

     

    Keep the feedback coming!

    Danny

  • Wednesday, October 10, 2007 7:11 PMkennykaz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thank you for your response.  Some of the solutions seem a little clumsy but I'm glad to see that most of my concerns have already been addressed or will be addressed in the future.  I should clarify a few things...

     

    -  I'm glad to see that the code generator is not required but the framework, tutorials and examples still seems to heavily favor that method.  Although I don't feel a need for full persistence ignorance, I'm glad that the option will be available and I think that many users will choose to use the framework based on this option.

     

    -  I'm really glad to hear that the framework only requires a private parameterless constructor.  To me this is a big deal.  However, it's a little disappointing that the framework can only map properties and not fields.  I'm glad to hear that a private property can be used for mapping but in constructing a class it seems that I would then need a private innerID field, a private InnerID property with both a "get" and a "set" and finally a public ID property that is read-only.  As well, for consistency, I might want to do this with all of my properties.  It's a bit inconvenient and seems like a problem that should not be too hard to solve (though easier said than done I'm sure).

     

    -  The example of a Validate or Save method on a base class was really just an example of what I meant when I said that I like my objects to be responsible for themselves.  I have no problem with the "unit of work" pattern and no matter what framework I end up using for data access it is almost sure that I would have a business layer framework of my own that would sit between my business layer and data access layer.  My goal is to find a data access framework that will require the least amount of code in the business layer framework, allows me to code the way I like and performs well.

     

    So those are my comments.  Here are my remaining questions...

     

    -  Does Linq (or more specifically DLinq) support inheritance in the way we discussed earlier?  Can you have a base class that does not need to map to the database but may contain fields that map to a database?

     

    -  It seems that, no matter what approach you use inside of the Entity Framework, an external mapping file is always required (.csdl).  Is that true?  I can't find any examples where that is not true.  I would think that if you use an interface, no attributes or mapping file would be necessary.  In addition, if attributes are used, interfaces and mapping files should not be necessary.  Finally, if a mapping file exists, there should really be no need for attributes or interfaces.  It's great when a code generator manages the synchronization of a database and multiple files but if one decides to create custom classes, it's kind of a pain to have to manage multiple files when the database changes.  With the current mapper that I am using, when I add a field to a table in the database I only need to add a field and a mapping attribute to the corresponding object in my business layer and I am done.  No need to change a mapping file or rewrite sql statements or anything else.

     

    -  How well does the framework perform?  I know optimization can be done through indexes in the database but are there certain ways of using that framework that perform better than others?  I've seen comments that IPOCO will perform better than POCO.  One of the nice things about "rolling my own" data mapper has been the ability to optimize it when necessary.  This includes creating new optimal ways of working with the data mapper such as the ability to lazy load or deep load based on different scenarios.  Does the entity framework support lazy loading and deep loading?  I think you are able to define sql when necessary which can solve a lot of problems.

     

    Looking forward to your response.

  • Wednesday, October 10, 2007 7:39 PMDaniel Simmons - MSFT Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    I'm not yet the DLINQ expert that I suspect I'll have to become over time, so I can't answer with confidence the question about whether or not it's possible to have the inheritance model you are looking for with DLINQ, but I suspect the answer is that it's not possible.  I do know it is possible with the entity framework.

     

    To address some of your other points about the EF:

     

    Mapping fields rather than just properties is something that will not be allowed in the first release, but it's certainly something we'll look at adding in a future release.

     

    Similarly, creating a variety of ways to specify mapping information is a part of our plans for future releases.  One possibility will be the current method (which honestly is more geared toward making making sure we have the infrastructure to handle all of our long term plans and toward enabling our visual tools for the first release), another possibility will be putting all of the mapping information in an external file with no interface or attribute demands so that we can have complete persistence ignorance--when we do this we're likely to have a different language as an option for authoring the mapping info that is more conducive to writing by hand.  Yet another way is, as you suggest, just specifying things in attributes and not needing a separate file at all.  Unfortunately, we just can't enable all of these options in the first release.

     

    With regard to performance, the EF definitely supports both lazy loading and deep loading, and we've done a LOT of work to optimize performance.  There's always more work that can be done, and there are often ways that you could do things a bit more efficiently if you were writing everything by hand for your specific scenario, but the truth is that for many scenarios we can actually do at least as well (sometimes even better) than what most folks would write by hand because we go to the point of things like generating and caching dynamic methods for setting properties, etc.  We're doing a lot more performance work before we hit RTM, so this area will only get better.

     

    - Danny

     

  • Wednesday, October 10, 2007 9:20 PMkennykaz Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     

    Thanks for your reply.  Your responsiveness to my questions has been terrific.  In the data mapper that I currently use, I am generating and caching dynamic methods for setting properties and fields so I'm glad to see you are using a similar approach as it means that I am probably heading in the right direction.  I'm looking forward to future releases of the product so that I will no longer have to maintain my own mapper and documentation.  For now my home grown solution seems like the best fit.  However, it is much easier to "sell" the idea of using a Microsoft product to another developer or team than convincing others that my data mapper will fit all of the needs of a project.  Thanks again for all of your help.