none
The LINQ To SQL ORM tools of VS2008 is very , very far from mature when dealing with Class Inheritance!!!!!! RRS feed

  • Question

  •  

    At first glance I am crazy with the linq to sql orm tools : refactoring the database , generating common entities classes and methods; while after a scritiny I find many drawbacks which makes my head ache!!... Especially in asp.net , such datacontext class behaves very poor when combining with LinqDataSource...

     

    A common case is : I have a base class  Person , and two derived class : Manager , Worker;

    Acutually just Person is generated by realy table in Datatable; And Manager , Worker

     

    Original   Person Table:

    ID:        common

    Name:   common

    Age:      common

    Title:      Manager field

    Tool:      Worker field

    Type:     ( sub class discriminator ) 

     

    Then I drag the Person table to design panel and system generates the base Person class , which holds just ID, Name, Age and Type fields;

    Then I manually create a Manager class ( holds Title , when Person's Type=1 ) , a Worker class( holds tool , when Person's Type = 2 ) , letting them inherits the Person class;

     

     

    Then in the generated db class , only the Person class is "perfectly"  set ; I can operate such class entities in LinqDataSource ( assign "TableName" as "Person" then everything becomes easy );  however , if I want  deal with Manager object, or Worker, troubles pour out ! Firstly I cannot simply assign a LinqDataSource's TableName with "Manager" ---- framework cannot directly retrieve such kind of class ( want not to mention db.Persons.OfType<Manager>() )  ,  the Insert  , Update operations over Manager are also impossible , for that They are not as "concrete" as Person when touching database access.   Using db.GetTable<Manager>() cause an failure exception.

     

    Still in this case , If  I want to make an association between Manager and Worker , that is : a manager can manage several workers; I cannot correctly point the "Worker" class to "Manager" to form such a tier , for that in the orm environment each association needs at least a "field" from "parent class" and a field from "child class" , while both  Manager's key field and Workers key field are Person's "ID" ,  so what I could do is just hooking  the Person to itself to represent its children -- Manager and Worker 's relationship  ---- it looks absurdly ,  but in current VS ORM version I find no better solution to solve such case. 

     

    Experts , who can tell me how to improve the model ??  Thanks !! And I beg Microsoft LINQ team to enhence the whole development system in the near furture !!

     

     

     

     

    Thursday, April 3, 2008 10:26 AM

Answers

  • All primary operations for subclasses should go via the superclasses table handler, however if you wish to perform queries against just the subclasses against the DataContext then you could write partial methods to return IQueryable with the subclass (type == subclass) expression appended automatically.

     

    Are you saying you only want the worker class to have a ManagerID field which should link to persons of type Manager?  Do managers not have managers?

     

    [)amien

    Monday, June 2, 2008 4:20 PM
    Moderator

All replies

  • All primary operations for subclasses should go via the superclasses table handler, however if you wish to perform queries against just the subclasses against the DataContext then you could write partial methods to return IQueryable with the subclass (type == subclass) expression appended automatically.

     

    Are you saying you only want the worker class to have a ManagerID field which should link to persons of type Manager?  Do managers not have managers?

     

    [)amien

    Monday, June 2, 2008 4:20 PM
    Moderator
  • I need to agree, I'm sorely disapointed with LINQ to SQLs support of inheritance.

    I'm creating a WebUserControl Base class that defines all of the CRUD operations, and works perfectly for almost every object in my model. The only problem is that if it is implemented with a derived class (defined in my dbml) nothing works.

    This is mainly due to DataContext.GetTable<T>()'s inability to detect the table attribute on parent classes.

    Consider a hypothetical model
    1    [Table(Name="dbo.Shapes")]
    2 [InheritanceMapping(Code="1", Type=typeof(Circle))]
    3 [InheritanceMapping(Code="2", Type=typeof(Square), IsDefault=true)]
    4 public class Shape
    5 {
    6 ...
    7 }
    8
    9 public class Circle : Shape
    10 {
    11 ...
    12 }
    13
    14 public class Square: Shape
    15 {
    16 ...
    17 }
    18
     
    I execute the following code, where T is a type parameter on the containing class

    1    Table<T> tbl = MyDataContext.GetTable<T>(); 
    If T is a derived type such as Square, an exception is thrown stating

    Could not retrieve a Table for inheritance subtype 'MyNamespace.Square', try Table of MyNamespace.Shape instead.

    I would have expected that if I passed Square as a type parameter to GetTable it would have been able to ascertain its table based on it's parent class. That is the point of in inheritance, isn't it? Furthermore, based on the exception message, it seems to have found out where to find my derived classes table on it's own. So it begs the question, why was the exception thrown in the first place?



    Monday, July 21, 2008 7:16 PM
  • GetTable<T> does what the method name says - it gets objects from the underlying table <T> so in your example Circle and Square are stored in the table Shape and so should be retrieved with GetTable<Shape>.

     

    If you wish to expose Circle and Square collections directly from the DataContext you can do by creating properties to expose them, e.g.

     

    public IQueryable<Circle> Circles { get { return from s in Shapes where s is Circle select s; } }

     

    Which would then let you perform queries such as:

     

    var newCircles = from c in dataContext.Circles where c.Radius == 6 select c;

     

    [)amien

    Monday, July 21, 2008 7:53 PM
    Moderator
  • I get the logic behind it, I just disagree with the implementation.

    Square and Circle are indeed stored table shape, there is no abiguity about it either. Furthermore, discover of the table (I can only assume) happens via reflection at some level (discovering the System.Table.Linq.Mapping.TableAttribute). C# does provide mechanisms that allow inheritance in reflection (discovering a base type's attributes where they are not defined on a derived type), and I would have expected such functionality when configuring a derived type from one of my LINQ to SQL classes.

    Defining an IQueryable in the data context for my derived classes may work in may situations. However, I am calling DataContext.GetTable<T>(), because I'm executing a query in a generic class, and I lack the ability to specificly reference anyone given IQueryable property in my DataContext.

    I ended up fixing the solution by using the template pattern, and allowing those few Classes that can't use GetTable<T> to override and implement their own logic for executing that specific query. This works just fine, and is clean enough for my standards at the moment, as the amount of exception are fairly small. However if would be ideal if I didn't have to implement this logic multiple times.

    My $0.02USD

    Thanks for the response!

    Tuesday, July 22, 2008 3:54 PM