Re: Finally which ORM tool?



Frans Bouma [C# MVP] <perseus.usenetNOSPAM@xxxxxxxxx> wrote:
If you track changes inside the entity, you don't need to. If you
don't have a session-oriented design, you have to track changes
elsewhere, so you don't have to put the burden onto the developer
to do things for the framework, the framework can decide what to do
by itself.

I think we were talking about a different type of change tracking.

I think there's just one: entity instance gets loaded into entity
class instance, entity instance in-memory gets changed. Which parts?
that's tracked, by the change tracking mechanism.

I thought we'd briefly gone into the realms of noticing that the
database copy had changed. My bad.

However, I seem to remember that Hibernate performs bytecode trickery
to keep changes within the object itself as well.

Don't compare hibernate with nhibernate, as hibernate 3 is different
from nhibernate (which is based on hibernate2). It's my understanding
that nhibernate uses the 'keep a copy around of the original values in
the session' method.

Ah... my bad again - it's Hibernate 3 which I'm most familiar with by a
long shot.

You're still sounding very black and white, and I simply don't
believe that there isn't a single advantage (to the user) of keeping
track of things in sessions. I have to say that when I was using
Hibernate it seemed a very natural way of working, partly because it
was very similar to using a transaction. Keeping a session open for
the length of a request just seemed to fit as an easy way of doing
something. I never experienced the "hell" of attach/detach, and
having opened the session and used that for everything else, I didn't
need to learn any "extras" to get uniqueness.

Also in distributed scenario's where entities got fetched in session
instance S1, distributed to some client, altered there and then they
came back and have to be saved with session instance S2?

Nope, I never had to do that. Now, it's possible that my situation is a
very rare one - but I'm not so sure. I'm not saying that your scenario
is rare either, just that there are pros and cons. For what I had to
do, the session was a natural way of achieving it.

I'm not saying that having a class which manages the activity with the
DB is bad, on the contrary. What I'm saying is that the object used to
load the entities should be in effect stateless. So shouldn't be tied
to an entity object.

Except you then need to introduce a new concept when you want database
identity preserved. When a session is already part of your mindset, and
that's what you flush at the end when you want to save (rather than
telling each individual object or tree to save itself) it's already
straightforward.

2-way databinding in webapps, passing entities across service
boundaries... 2 examples where you have to tell the framework what
to do while it's the job of the framework to find out what to do.

Ah, databinding - I've never been a fan of that to start with, to be
honest.

Me neither, but the vast majority of people out there uses it. :)

:)

Too much black magic which only works if you happen to want
to work in exactly the way that was anticipated. At least, that's
been my experience of it in every scenario I've seen. It does work
pretty well for displaying stuff - but making it 2-way just has so
many problems. With any luck WPF improves matters somewhat as far as
thick clients are concerned...

It's not that bad. Avoiding it has the implication that you have to
write the glue between control and object yourself, which can be
painful and buggy as well, simply because it's boring code.

Oh absolutely. The difference is that if you then need to fix something
to behave in a particular way, you can do so. I suspect there's a nice
solution waiting in the wings somewhere, but I haven't used it yet. As
I say, I have hopes for WPF...

Sure if you don't mind to do the extra work, it's not a problem.
Also, with hibernate based frameworks, you don't get a lot of entity
management anyway. I mean:
myOrder.Customer = myCustomer;
doesn't make this true:
myCustomer.Orders.Contains(myOrder);

Not unless you implement the recommended patterns (which would keep
the association consistent). I admit it's a disadvantage to have to
do all this manually.

exactly. If you have to write manually all the code to keep things
going, sure, then there's no problem. But the point of using a
framework is that you DON'T have to write the code manually: it's been
done for you.

Preferrably, yes - but given the rest of what Hibernate does for me,
I'm happy enough to do this myself. Alternatively, I can still use a
code generator to create entities to start with; a hybrid between the
"pure code generation" and "no code generation" solutions.

I've never had the need to do that with Hibernate, but I've always
known it's an option if I really wanted it :)

Though back to the small space of a webpage which posts back: the
state of the page has to be pulled from somewhere. That's of course
ok, there are facilities for that. The problem is though, if you
track changes in an object outside the entities, you either have to
keep that in memory as well (bad) or you have to rely on the
developer to tell you what the state of the entities is. (bad too,
as it implies babysitting by the developer).

As I say, I thought Hibernate kept track of what had changed within
the entity itself too. I don't know about NHibernate though, or how
serialization affects this.

If I'm not mistaken, they use the same mechanism as Linq to Sql does:
keep the original values in the session, and compare original with
current to see what the changes are.

If, as you say, NHibernate is based on Hibernate2 instead of
Hibernate3, you're probably right.

I can't say I remember ever actually needing to attach/detach. I know
that it's available, but I can't remember needing to use it. If I
did need to use it, it clearly didn't cause me enough pain to make it
memorable.

If Hibernate 3 has in-entity change management through bytecode
manipulation (or post-compilation, as it's used by some .net o/r
mappers), then you don't have attach/detach problems as you don't need
to: the session doesn't keep track of the original values, they're
inside the entity object.

You may still want to detach or re-attach though, for other reasons -
to make the re-attached entity part of a new session and have it saved
when that session is saved, participate in uniqueness etc.

<snip>

That's the fundamental difference and that difference is going to
cause problems, simply because the linq query object contains a
session.

Also, if you pass a variable to the query, the value the variable
has at EXECUTION time is used, not at CREATION time:

That certainly needs to be clearly understood - but I'd say it's
useful, too, in cases where you need to do the same query multiple
times but with different parameters.

Isn't that going into the red zone of 'magic programming' ? I mean,
you have a local variable, even if it's a value typed variable, and you
have a linq query and by changing the variable's value, you manipulate
the linq query IF you're executing it at that moment.

It's probably slightly "magic" at the moment. I don't think it will be
for long. Sooner or later, devs are going to have to understand what
closures really are, and how with captured variables it really is the
variable which is captured, not its value.

Don't forget that it's not just LINQ to SQL we're talking about here -
this is true for LINQ to Objects as well as anywhere else you might use
an anonymous function.

Captured variables always need to be handled with care, and I can see
that it could well trip up novices, but I don't think it's
unreasonable.

Sure, but the code LOOKS the same as:
int foo = GetFoo();
bool b = (bar == foo);

b isn't suddenly affected if foo is changed after this. Though if I do:
var q = from x in metadata.SomeEntity
where x.Foo == foo
select x;

q is affected if I change foo AFTER this query and BEFORE execution.
Why is this comparison expression suddenly different from the
expression of b? The first is executed at that moment, the latter is
executed somewhere later, but you have to follow q to found out when.
That SHOULDN'T be important, simply because q LOOKS like a declaration,
constructed at the spot where q is declared.

And it *is* a declaration, but one which captures the variables. I
really don't think it's that bad, once you get used to it - it's very
similar to the whole "passing a reference type argument by value
doesn't mean all the data is copied, just the reference". Once you
accept where changes will be reflected, it's quite easy to work with
that.

So the query isn't a query definition alone, it's also the
resultset.

No, the query itself is a query definition alone. It's only the
enumerator you get when you call GetEnumerator() which relates to the
result set.

It's an IEnumerable<T>, and therefore a resultset. If it would be a
definition alone, the queries of CHOPS would have been fetched, simply
because the declaration construction was with 'CHOPS'.

I don't see the logic in your first definition. Suppose it didn't
implement IEnumerable<T> but had an Execute() method which gave back an
IEnumerator<T> instead - in other words, we *just* changed a method
name and in doing so removed an interface implementation. How can that
change whether the object is itself a resultset or not? Or would it
still be a resultset in your view?

The query itself doesn't contain the data, it simply contains all the
information required to fetch the data. That doesn't make it a
resultset in my view. It's all a matter of definition though.

It's very natural. Also, because in that last example it's not
deferred executed, the query is created when the var q statement is
executed in code, so the changed variable problem isn't there.

But equally the ability to reuse the query very simply by changing
the variables isn't there either. If you want to avoid the meaning of
the query being changed, either copy the variable values or just
don't change the variables.

Sure, though I don't like the similarity of the code statements which
tend to behave completely different at runtime. As this is a runtime
issue, it can lead to test-burdens.

They for example could have opted for a system where you could get
access to the parameters in the query to alter them for each run.

You can do that for LINQ to SQL, but it's rather harder to do it for
LINQ in general, unless you want *everything* to go via expression
trees instead of lambda expressions, or make lambda expressions
significantly less powerful.

Variable capture is an important part of the power of LINQ IMO, but it
certainly does need to be understood - and I'm sure it'll bite people
while they get the hang of it.

I've always found the deferred execution very natural, both in LINQ
and Hibernate - I create a query, do other things if necessary, and
then use the query when I'm ready. Why should creating the query
execute it immediately?

No, that's not what I meant. What I meant was: you declare a query
somewhere, e.g. in a method you call to formulate the query, then
execute it somewhere else, however the query declaration is already
fixed, so you can alter it, by changing a parameter on a predicate, but
not by changing a local variable's value.

The fact that the *execution* doesn't happen at the *declaration* means
it's deferred execution by every other use of the phrase that I've ever
seen.

You're using "deferred execution" to mean what I'd probably describe as
"deferred parameter evaluation". It's an interesting topic to talk
about, but I'd prefer it if we didn't keep calling it "deferred
execution".

From MSDN:

<quote>
As stated previously, when the query is designed to produce a sequence
of values, the query variable itself only stores the query commands.
The actual execution of the query is deferred until you iterate over
the query variable in a foreach loop. This concept is referred to in
the documentation as deferred execution.
</quote>

Now, you also bring up another topic: separating the query from its
data connection. You can't easily separate it from its whole data
context in terms of the types involved, because at that point you lose
a lot of the benefits of LINQ - but I could certainly envisage
separating it from a "live" context. I don't know what LINQ to Entities
will have, but I wouldn't be at all surprised to see that in there.

I think in LINQ to SQL you can do this with CompiledQuery.Compile, but
I haven't tried it myself. I don't know whether this *also* keeps the
values of variables at the point of compilation, but if it does then
it's a fairly simple way of keeping people out of trouble.

I think the rest of your post pretty much falls into the bits I've
talked about above, so I've snipped rather than repeating myself :)

--
Jon Skeet - <skeet@xxxxxxxxx>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
.



Relevant Pages

  • Re: Finally which ORM tool?
    ... Also, if you pass a variable to the query, the value the ... you have a linq query and by changing the variable's value, ... q is affected if I change foo AFTER this query and BEFORE execution. ... And it is a declaration, but one which captures the variables. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Finally which ORM tool?
    ... the session' method. ... able to execute the query by itself. ... has at EXECUTION time is used, ... That SHOULDN'T be important, simply because q LOOKS like a declaration, ...
    (microsoft.public.dotnet.languages.csharp)
  • RE: Touble With Dates
    ... Session altered. ... Every function adds execution cost to your script. ... But who would want to have a query only match a down-to-the-second ... TRUNC will trucate the value to the date only so ...
    (perl.dbi.users)
  • Re: Finally which ORM tool?
    ... things for the framework, the framework can decide what to do by itself. ... the client would let you effectively have a "fake" session that you ... attaching graphs) and together with deferred execution of linq ... able to execute the query by itself. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: CBO & different execution plans
    ... query, ... Oracle 10g generates a non-performant execution plan. ... rows being returned by the SQL statement. ... starting a new session and altering that session one parameter at a ...
    (comp.databases.oracle.server)