I'm struggling a bit with generics and inheritance. Basically, I want this:

IA //Interface A
IB //Interface B
CBaseA : IA //Base class A
CBaseB : IB //Base class B

Generic class A
where TCA : CA<TCA, TCB>
where TCB: CB<TCA, TCB>

Generic class B
where TCA : CA<TCA, TCB>
where TCB: CB<TCA, TCB>
MyA : CA<CustomA, CustomB> //One of my implementations, hierarchy root
MyB : CB<CustomA, CustomB> // -||-
MyOtherA : CA<CustomA, CustomB> //One of my implementations, hierarchy root
MyOtherB : CB<CustomA, CustomB> // -||-

CA<TCA, TCB> has an EntitySet<TCB> and CB<TCA, TCB> has a field TCA - ie a M:1-relation

My problem: Currently I can't access the relation between CA and CB from the base classes, or the interfaces. However, if I define the relation there I won't have a typed relation between CA and CB anymore, making it significantly harder to query. I want an "untyped" relation between CBaseA and CBaseB, and a typed relation between any childs of CA and CB

Is there any solution? Any straightforward solution? Writing a custom LINQ expression rewriter? (How? I can't find the compiler-attributes the manual mentions)

Edit: I see I've missed some details: CBaseA, CBaseB, CA and CB are all abstract classes.

My conclusion so far is that I need to keep the relation in the CA/CB-classes and then "wrap" it somehow in CBaseA/CBaseB (and the interfaces), and I need some kind of rewriting

Edit2: My new conclusion is that I won't be able to take that route since the actual implementation is totally unknown at runtime..

As far as I'm concerned, I need to have to properties, one in a base class, and one in an inherited class, that are essentially the same, kind of a hard link in a file system. However, an attempt to do so gives me an exception about duplicate keys..

Now I'm thinking I might be able to declare the relationship in the base classes, and then add validation, properties and rewriters for the inherited classes to ensure type safety.. I think that should work? =)

asked Oct 04 '12 at 07:47

Onkelborg's gravatar image


edited Oct 04 '12 at 11:44

One Answer:

I think I've got a working solution, I haven't tested it enough yet though. However, my solution is to keep the relationship in the base class, so it's kind of untyped. However, in one of the classes I've added a custom PropertyConstraintAspect to the field, in the other I've inherited the EntitySet and added some validation to the OnAdding-method.

Then I've added a property to the classes, one TA and one IQueryable<tb>. The first just cast, the second call .Select() and casts.

Then I've added some custom LINQ rewriters to the domain (config.LinqExtensions.Register) that creates expressions doing exactly what the properties does.

The typed IQueryable< B > is read only of course, so I have to add entites to the untyped EntitySet, however, it's a small price to pay. I won't get any fancy compile time errors though.. :/

answered Oct 04 '12 at 19:17

Onkelborg's gravatar image


edited Oct 04 '12 at 19:24

I've done a small modification, the rewritten iqueryable now does something along the path: Query.All().Where(x => x.Parent == this) - avoiding lots of unions.. :)

(Oct 04 '12 at 19:55) Onkelborg Onkelborg's gravatar image

I've tested it somewhat extensively and it appears to be working good :)

(Oct 05 '12 at 09:04) Onkelborg Onkelborg's gravatar image

Hello, Onkelborg. I'm glad you have your issue fixed.

(Oct 05 '12 at 09:32) Denis Krjuchkov Denis%20Krjuchkov's gravatar image

Me too :) Hopefully someone have some use of this sometime in the future while searching the forums :)

Btw, I'm really impressed by the performance of the generated sql. I've tweaked my expressions a bit, and now I have both type safety and really well optimized sql.

(Oct 05 '12 at 10:11) Onkelborg Onkelborg's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

powered by OSQA