PC Review


Reply
Thread Tools Rate Thread

Building expression trees to filter derived entity classes

 
 
Fritz
Guest
Posts: n/a
 
      17th Mar 2009
Hi,

How can a access members of defered entity classes using an expression tree?
The problem: as soon a filtered entity is of another derived entity class.

Having derived entity classes like:

public abstract class Profile {
public ProfileType ProfileType;
}

public class ProfileCircular : Profile {
public float Diameter;
}

public class ProfileRectangle : Profile {
public float SizeX;
public float SizeY;
}

The goal is to dynamically building expression trees to filter objects of
this classes.
All works fine if I filter for Profile.ProfileType, which is a member of the
entity base class. But how can I filter mixed objects of types
ProfileCircular and ProfileRectangle?
For example the filter should extract all ProfileCircular objects with
Diameter >= 40.0.
The expression tree build to do so looks like:

Lambda - Expression`1
AndAlso - BinaryExpression
Conditional - ConditionalExpression
TypeIs - TypeBinaryExpression
Parameter - ParameterExpression
GreaterThanOrEqual - BinaryExpression
MemberAccess - MemberExpression
TypeAs - UnaryExpression
Parameter - ParameterExpression
Constant - ConstantExpression
Constant - ConstantExpression

At execution time of query an InvalidOperationException is raised saying:
"Member access Diameter' of 'ProfileCircular' not legal on type
'ProfileRectangle."

I expected that member access to Diameter would not be executed on objects
of type ProfileRectangle due to the ConditionalException testing for "TypeIs
ProfileCircular".

Thanks for any help, Fritz
 
Reply With Quote
 
 
 
 
Pavel Minaev
Guest
Posts: n/a
 
      17th Mar 2009
On Mar 17, 10:18*am, Fritz <Fr...@discussions.microsoft.com> wrote:
> Hi,
>
> How can a access members of defered entity classes using an expression tree?
> The problem: as soon a filtered entity is of another derived entity class..
>
> Having derived entity classes like:
>
> public abstract class Profile {
> * *public ProfileType ProfileType;
>
> }
>
> public class ProfileCircular : Profile {
> * *public float Diameter;
>
> }
>
> public class ProfileRectangle : Profile {
> * *public float SizeX;
> * *public float SizeY;
>
> }
>
> The goal is to dynamically building expression trees to filter objects of
> this classes.
> All works fine if I filter for Profile.ProfileType, which is a member of the
> entity base class. But how can I filter mixed objects of types
> ProfileCircular and ProfileRectangle?
> For example the filter should extract all ProfileCircular objects with
> Diameter >= 40.0.
> The expression tree build to do so looks like:
>
> Lambda *- *Expression`1
> * *AndAlso *- *BinaryExpression
> * * * Conditional *- *ConditionalExpression
> * * * * *TypeIs *- *TypeBinaryExpression
> * * * * * * Parameter *- *ParameterExpression
> * * * * *GreaterThanOrEqual *- *BinaryExpression
> * * * * * * MemberAccess *- *MemberExpression
> * * * * * * * *TypeAs *- *UnaryExpression
> * * * * * * * * * Parameter *- *ParameterExpression
> * * * * * * Constant *- *ConstantExpression
> * * * * *Constant *- *ConstantExpression
>
> At execution time of query an InvalidOperationException is raised saying:
> "Member access Diameter' of 'ProfileCircular' not legal on type
> 'ProfileRectangle."
>
> I expected that member access to Diameter would not be executed on objects
> of type ProfileRectangle due to the ConditionalException testing for "TypeIs
> ProfileCircular".


Please clarify what flavor of LINQ you're using (to objects, SQL, EF
etc). Also, can you include the value returned by ToString() for the
expression tree that you've built (it's hard to read it the way it's
spelt out in your post, and it omits actual values in the nodes)?

 
Reply With Quote
 
Fritz
Guest
Posts: n/a
 
      17th Mar 2009
"Pavel Minaev" wrote:
>
> Please clarify what flavor of LINQ you're using (to objects, SQL, EF
> etc). Also, can you include the value returned by ToString() for the
> expression tree that you've built (it's hard to read it the way it's
> spelt out in your post, and it omits actual values in the nodes)?
>
>


Hi Pavel

The expression tree in literal is:

Lambda - e => IIF((e Is ProfileCircular), (Convert((e As
ProfileCircular).Diameter) >= 40), True)
Conditional - IIF((e Is ProfileCircular), (Convert((e As
ProfileCircular).Diameter) >= 40), True)
TypeIs - (e Is ProfileCircular)
Parameter - e
GreaterThanOrEqual - (Convert((e As ProfileCircular).Diameter) >= 40)
Convert - Convert((e As ProfileCircular).Diameter)
MemberAccess - (e As ProfileCircular).Diameter
TypeAs - (e As ProfileCircular)
Parameter - e
Constant - 40
Constant - True


Flavor is LINQ to SQL. Here is the code where the expression tree is applieed:

Expression<Func<Profile, bool>> filterExpression =
filter.GetExpression<Profile>();

var dal = DalFactory.Instance.CreateDal<Profile, IQueryable<Profile>,
Int32>();
var result =
dal.ReadAll()
.Where(filterExpression)
.Select(e => e);

Thanks for investigation, Fritz
 
Reply With Quote
 
Pavel Minaev
Guest
Posts: n/a
 
      17th Mar 2009
On Mar 17, 11:23*am, Fritz <Fr...@discussions.microsoft.com> wrote:
> "Pavel Minaev" wrote:
>
> > Please clarify what flavor of LINQ you're using (to objects, SQL, EF
> > etc). Also, can you include the value returned by ToString() for the
> > expression tree that you've built (it's hard to read it the way it's
> > spelt out in your post, and it omits actual values in the nodes)?

>
> Hi Pavel
>
> The expression tree in literal is:
>
> Lambda *- *e => IIF((e Is ProfileCircular), (Convert((e As
> ProfileCircular).Diameter) >= 40), True)
> * *Conditional *- *IIF((e Is ProfileCircular), (Convert((e As
> ProfileCircular).Diameter) >= 40), True)
> * * * TypeIs *- *(e Is ProfileCircular)
> * * * * *Parameter *- *e
> * * * GreaterThanOrEqual *- *(Convert((e As ProfileCircular).Diameter) >= 40)
> * * * * *Convert *- *Convert((e As ProfileCircular).Diameter)
> * * * * * * MemberAccess *- *(e As ProfileCircular).Diameter
> * * * * * * * *TypeAs *- *(e As ProfileCircular)
> * * * * * * * * * Parameter *- *e
> * * * * *Constant *- *40
> * * * Constant *- *True
>
> Flavor is LINQ to SQL. Here is the code where the expression tree is applieed:
>
> Expression<Func<Profile, bool>> filterExpression =
> filter.GetExpression<Profile>();
>
> var dal = DalFactory.Instance.CreateDal<Profile, IQueryable<Profile>,
> Int32>();
> var result =
> * * dal.ReadAll()
> * * .Where(filterExpression)
> * * .Select(e => e);


I strongly suspect that this is a LINQ to SQL limitation. Having
written my own query-translation ORM in the past, I know that handling
"is/as" (or analogs) correctly with semantics identical to the host
language can be quite a challenge in SQL, so I'm not surprised there.
Interestingly, LINQ to SQL docs claim that, while C-style casts aren't
supported by the translator in projections, operators "is" and "as"
are, with no other comments. I've made a simple console app with SQL
server database, and tested inheritance in a query identical to yours
("o is Derived1 ? (o as Derived1).Member == 123 : true"), and it
worked fine for me, even with objects of all possible types in the
table.

I'm not so sure where to go from here now... are you sure you have set
up the inheritance correctly in your LINQ to SQL mapping? Aside from
that, I can't really think of anything. Maybe if you provide your
table definition for the hierarchy, and the mapping, it would be
possible to repro that and see what's wrong.
 
Reply With Quote
 
Fritz
Guest
Posts: n/a
 
      18th Mar 2009
"Pavel Minaev" wrote:
>
> I'm not so sure where to go from here now... are you sure you have set
> up the inheritance correctly in your LINQ to SQL mapping? Aside from
> that, I can't really think of anything. Maybe if you provide your
> table definition for the hierarchy, and the mapping, it would be
> possible to repro that and see what's wrong.
>


Here the code for translating SQL data to domain classes:

IQueryable<DomainModel.Profile> result =
from p in DC.Profiles
select
p.ProfileTyp == (ushort)DomainModel.ProfileType.Rund ?
new DomainModel.ProfileCircular
{
// if next statement is missing
// exception "has no supported translation to SQL"
// would be raised when using ProfileTyp as parameter
// in expression tree for dynamic filtering
ProfileTyp = (DomainModel.ProfileType)p.ProfileTyp,
ID = p.ID,
Name = p.Name,
Diameter = (p as CircularProfile).Diameter,
Comment = p.Comment,
modified = p.modified,
Version = p.Version
} :
p.ProfileTyp == (ushort)DomainModel.ProfileType.Rechteck ?
new DomainModel.ProfileRectangle
{
ProfileTyp = (DomainModel.ProfileType)p.ProfileTyp,
ID = p.ID,
Name = p.Name,
Size_X = (p as RectangleProfile).Size_X,
Size_Y = (p as RectangleProfile).Size_Y,
EdgeRadius = (p as RectangleProfile).EdgeRadius,
Comment = p.Comment,
modified = p.modified,
Version = p.Version
} :
p.ProfileTyp == (ushort)DomainModel.ProfileType.Sonder ?
new DomainModel.ProfileArbitrary
{
ProfileTyp = (DomainModel.ProfileType)p.ProfileTyp,
ID = p.ID,
Name = p.Name,
Size_X = (p as ArbitraryProfile).Size_X,
Size_Y = (p as ArbitraryProfile).Size_Y,
CenterOfArea_X = (p as ArbitraryProfile).CenterOfArea_X,
CenterOfArea_Y = (p as ArbitraryProfile).CenterOfArea_Y,
Drawing = (p as ArbitraryProfile).Drawing,
Comment = p.Comment,
modified = p.modified,
Version = p.Version
} :
new DomainModel.Profile();
return result;





Here the mapping definition:

[Table(Name = "Profiles")]
[InheritanceMapping(Code = "0", Type = typeof(CircularProfile), IsDefault =
true)]
[InheritanceMapping(Code = "1", Type = typeof(RectangleProfile))]
[InheritanceMapping(Code = "10", Type = typeof(ArbitraryProfile))]
public partial class Profile : INotifyPropertyChanging, INotifyPropertyChanged
{

private static PropertyChangingEventArgs emptyChangingEventArgs = new
PropertyChangingEventArgs(String.Empty);

private int _ProfileID;

private ushort _ProfileTyp;

private string _Name;

private string _Comment;

private System.Nullable<System.DateTime> _modified;

private System.Data.Linq.Binary _Stamp;

private EntitySet<Pipe> _Pipes;

private EntitySet<BendTool> _Tools;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnIDChanging(int value);
partial void OnIDChanged();
partial void OnProfileTypChanging(ushort value);
partial void OnProfileTypChanged();
partial void OnNameChanging(string value);
partial void OnNameChanged();
partial void OnCommentChanging(string value);
partial void OnCommentChanged();
partial void OnmodifiedChanging(System.Nullable<System.DateTime> value);
partial void OnmodifiedChanged();
partial void OnVersionChanging(System.Data.Linq.Binary value);
partial void OnVersionChanged();
#endregion

public Profile()
{
this._Pipes = new EntitySet<Pipe>(new Action<Pipe>(this.attach_Pipes),
new Action<Pipe>(this.detach_Pipes));
this._Tools = new EntitySet<BendTool>(new
Action<BendTool>(this.attach_Tools), new Action<BendTool>(this.detach_Tools));
OnCreated();
}

[Column(Storage = "_ProfileID", AutoSync = AutoSync.OnInsert, DbType =
"Int NOT NULL IDENTITY", IsPrimaryKey = true, IsDbGenerated = true)]
public int ID
{
get
{
return this._ProfileID;
}
set
{
if ((this._ProfileID != value))
{
this.OnIDChanging(value);
this.SendPropertyChanging();
this._ProfileID = value;
this.SendPropertyChanged("ID");
this.OnIDChanged();
}
}
}

[Column(Storage = "_ProfileTyp", IsDiscriminator = true)]
public ushort ProfileTyp
{
get
{
return this._ProfileTyp;
}
set
{
if ((this._ProfileTyp != value))
{
this.OnProfileTypChanging(value);
this.SendPropertyChanging();
this._ProfileTyp = value;
this.SendPropertyChanged("ProfileTyp");
this.OnProfileTypChanged();
}
}
}

[Column(Storage = "_Name", DbType = "NVarChar(50)", CanBeNull = false)]
public string Name
{
get
{
return this._Name;
}
set
{
if ((this._Name != value))
{
this.OnNameChanging(value);
this.SendPropertyChanging();
this._Name = value;
this.SendPropertyChanged("Name");
this.OnNameChanged();
}
}
}

[Column(Storage = "_Comment", DbType = "NVarChar(300)")]
public string Comment
{
get
{
return this._Comment;
}
set
{
if ((this._Comment != value))
{
this.OnCommentChanging(value);
this.SendPropertyChanging();
this._Comment = value;
this.SendPropertyChanged("Comment");
this.OnCommentChanged();
}
}
}

[Column(Storage = "_modified", DbType = "DateTime", UpdateCheck =
UpdateCheck.Never)]
public System.Nullable<System.DateTime> modified
{
get
{
return this._modified;
}
set
{
if ((this._modified != value))
{
this.OnmodifiedChanging(value);
this.SendPropertyChanging();
this._modified = value;
this.SendPropertyChanged("modified");
this.OnmodifiedChanged();
}
}
}

[Column(Storage = "_Stamp", AutoSync = AutoSync.Always, DbType =
"TIMESTAMP", CanBeNull = false, IsDbGenerated = true, IsVersion = true)]
public System.Data.Linq.Binary Version
{
get
{
return this._Stamp;
}
set
{
if ((this._Stamp != value))
{
this.OnVersionChanging(value);
this.SendPropertyChanging();
this._Stamp = value;
this.SendPropertyChanged("Version");
this.OnVersionChanged();
}
}
}

[Association(Name = "Profile_Pipe", Storage = "_Pipes", ThisKey = "ID",
OtherKey = "ProfileID")]
public EntitySet<Pipe> Pipes
{
get
{
return this._Pipes;
}
set
{
this._Pipes.Assign(value);
}
}

[Association(Name = "Profile_BendTool", Storage = "_Tools", ThisKey =
"ID", OtherKey = "ProfileID")]
public EntitySet<BendTool> Tools
{
get
{
return this._Tools;
}
set
{
this._Tools.Assign(value);
}
}

public event PropertyChangingEventHandler PropertyChanging;

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void SendPropertyChanging()
{
if ((this.PropertyChanging != null))
{
this.PropertyChanging(this, emptyChangingEventArgs);
}
}

protected virtual void SendPropertyChanged(String propertyName)
{
if ((this.PropertyChanged != null))
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

private void attach_Pipes(Pipe entity)
{
this.SendPropertyChanging();
entity.Profile = this;
}

private void detach_Pipes(Pipe entity)
{
this.SendPropertyChanging();
entity.Profile = null;
}

private void attach_Tools(BendTool entity)
{
this.SendPropertyChanging();
entity.Profile = this;
}

private void detach_Tools(BendTool entity)
{
this.SendPropertyChanging();
entity.Profile = null;
}
}

public partial class CircularProfile : Profile
{

private System.Nullable<float> _Diameter;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnDiameterChanging(System.Nullable<float> value);
partial void OnDiameterChanged();
#endregion

public CircularProfile()
{
OnCreated();
}

[Column(Storage = "_Diameter")]
public System.Nullable<float> Diameter
{
get
{
return this._Diameter;
}
set
{
if ((this._Diameter != value))
{
this.OnDiameterChanging(value);
this.SendPropertyChanging();
this._Diameter = value;
this.SendPropertyChanged("Diameter");
this.OnDiameterChanged();
}
}
}
}

public partial class NonCircularProfile : Profile
{

private System.Nullable<float> _Size_X;

private System.Nullable<float> _Size_Y;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnSize_XChanging(System.Nullable<float> value);
partial void OnSize_XChanged();
partial void OnSize_YChanging(System.Nullable<float> value);
partial void OnSize_YChanged();
#endregion

public NonCircularProfile()
{
OnCreated();
}

[Column(Storage = "_Size_X")]
public System.Nullable<float> Size_X
{
get
{
return this._Size_X;
}
set
{
if ((this._Size_X != value))
{
this.OnSize_XChanging(value);
this.SendPropertyChanging();
this._Size_X = value;
this.SendPropertyChanged("Size_X");
this.OnSize_XChanged();
}
}
}

[Column(Storage = "_Size_Y")]
public System.Nullable<float> Size_Y
{
get
{
return this._Size_Y;
}
set
{
if ((this._Size_Y != value))
{
this.OnSize_YChanging(value);
this.SendPropertyChanging();
this._Size_Y = value;
this.SendPropertyChanged("Size_Y");
this.OnSize_YChanged();
}
}
}
}

public partial class RectangleProfile : NonCircularProfile
{

private System.Nullable<float> _EdgeRadius;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnEdgeRadiusChanging(System.Nullable<float> value);
partial void OnEdgeRadiusChanged();
#endregion

public RectangleProfile()
{
OnCreated();
}

[Column(Storage = "_EdgeRadius")]
public System.Nullable<float> EdgeRadius
{
get
{
return this._EdgeRadius;
}
set
{
if ((this._EdgeRadius != value))
{
this.OnEdgeRadiusChanging(value);
this.SendPropertyChanging();
this._EdgeRadius = value;
this.SendPropertyChanged("EdgeRadius");
this.OnEdgeRadiusChanged();
}
}
}
}

public partial class ArbitraryProfile : NonCircularProfile
{

private System.Nullable<float> _CenterOfArea_X;

private System.Nullable<float> _CenterOfArea_Y;

private System.Data.Linq.Binary _Drawing;

#region Extensibility Method Definitions
partial void OnLoaded();
partial void OnValidate(System.Data.Linq.ChangeAction action);
partial void OnCreated();
partial void OnCenterOfArea_XChanging(System.Nullable<float> value);
partial void OnCenterOfArea_XChanged();
partial void OnCenterOfArea_YChanging(System.Nullable<float> value);
partial void OnCenterOfArea_YChanged();
partial void OnDrawingChanging(System.Data.Linq.Binary value);
partial void OnDrawingChanged();
#endregion

public ArbitraryProfile()
{
OnCreated();
}

[Column(Storage = "_CenterOfArea_X")]
public System.Nullable<float> CenterOfArea_X
{
get
{
return this._CenterOfArea_X;
}
set
{
if ((this._CenterOfArea_X != value))
{
this.OnCenterOfArea_XChanging(value);
this.SendPropertyChanging();
this._CenterOfArea_X = value;
this.SendPropertyChanged("CenterOfArea_X");
this.OnCenterOfArea_XChanged();
}
}
}

[Column(Storage = "_CenterOfArea_Y")]
public System.Nullable<float> CenterOfArea_Y
{
get
{
return this._CenterOfArea_Y;
}
set
{
if ((this._CenterOfArea_Y != value))
{
this.OnCenterOfArea_YChanging(value);
this.SendPropertyChanging();
this._CenterOfArea_Y = value;
this.SendPropertyChanged("CenterOfArea_Y");
this.OnCenterOfArea_YChanged();
}
}
}

[Column(Storage = "_Drawing", DbType = "VARBINARY(320)")]
public System.Data.Linq.Binary Drawing
{
get
{
return this._Drawing;
}
set
{
if ((this._Drawing != value))
{
this.OnDrawingChanging(value);
this.SendPropertyChanging();
this._Drawing = value;
this.SendPropertyChanged("Drawing");
this.OnDrawingChanged();
}
}
}
}


 
Reply With Quote
 
Pavel Minaev
Guest
Posts: n/a
 
      18th Mar 2009
On Mar 18, 2:29*am, Fritz <Fr...@discussions.microsoft.com> wrote:
> "Pavel Minaev" wrote:
>
> > I'm not so sure where to go from here now... are you sure you have set
> > up the inheritance correctly in your LINQ to SQL mapping? Aside from
> > that, I can't really think of anything. Maybe if you provide your
> > table definition for the hierarchy, and the mapping, it would be
> > possible to repro that and see what's wrong.

>
> Here the code for translating SQL data to domain classes:
>
> IQueryable<DomainModel.Profile> result =
> * * from p in DC.Profiles
> * * select
> * * * * p.ProfileTyp == (ushort)DomainModel.ProfileType.Rund ?
> * * * * * * new DomainModel.ProfileCircular
> * * * * * * {
> * * * * * * * * // if next statement is missing
> * * * * * * * * // exception "has no supported translation to SQL"
> * * * * * * * * // would be raised when using ProfileTyp as parameter
> * * * * * * * * // in expression tree for dynamic filtering
> * * * * * * * * ProfileTyp = (DomainModel.ProfileType)p..ProfileTyp,
> * * * * * * * * ID = p.ID,
> * * * * * * * * Name = p.Name,
> * * * * * * * * Diameter = (p as CircularProfile).Diameter,
> * * * * * * * * Comment = p.Comment,
> * * * * * * * * modified = p.modified,
> * * * * * * * * Version = p.Version
> * * * * * * } :
> * * * * p.ProfileTyp == (ushort)DomainModel.ProfileType.Rechteck ?
> * * * * * * new DomainModel.ProfileRectangle
> * * * * * * {
> * * * * * * * * ProfileTyp = (DomainModel.ProfileType)p..ProfileTyp,
> * * * * * * * * ID = p.ID,
> * * * * * * * * Name = p.Name,
> * * * * * * * * Size_X = (p as RectangleProfile).Size_X,
> * * * * * * * * Size_Y = (p as RectangleProfile).Size_Y,
> * * * * * * * * EdgeRadius = (p as RectangleProfile).EdgeRadius,
> * * * * * * * * Comment = p.Comment,
> * * * * * * * * modified = p.modified,
> * * * * * * * * Version = p.Version
> * * * * * * } :
> * * * * p.ProfileTyp == (ushort)DomainModel.ProfileType.Sonder ?
> * * * * * * new DomainModel.ProfileArbitrary
> * * * * * * {
> * * * * * * * * ProfileTyp = (DomainModel.ProfileType)p..ProfileTyp,
> * * * * * * * * ID = p.ID,
> * * * * * * * * Name = p.Name,
> * * * * * * * * Size_X = (p as ArbitraryProfile).Size_X,
> * * * * * * * * Size_Y = (p as ArbitraryProfile).Size_Y,
> * * * * * * * * CenterOfArea_X = (p as ArbitraryProfile).CenterOfArea_X,
> * * * * * * * * CenterOfArea_Y = (p as ArbitraryProfile).CenterOfArea_Y,
> * * * * * * * * Drawing = (p as ArbitraryProfile).Drawing,
> * * * * * * * * Comment = p.Comment,
> * * * * * * * * modified = p.modified,
> * * * * * * * * Version = p.Version
> * * * * * * } :
> * * * * * * new DomainModel.Profile();
> return result;


Alright, I have successfully repro'd your problem with this with some
simplified code. It seems that the problem only manifests itself when
you project the your LINQ to SQL entity objects onto some other POCO
("domain") objects, and then query over the latter.

I can't say specifically why it is the case, but I have a strong
suspicion. LINQ to SQL is still trying to process the entire query,
including the part of it that deals with your projected domain
classes. Now, when you use operators is/as directly on the entity
objects, it knows how to map the check to a comparison against a
discriminator field. However, for your domain classes, it does not
have that mapping, and it is not smart enough to deduce it from your
LINQ query by itself. So effectively any use of operators "is" and
"as" on the domain objects in the query messes it up. You can observe
it if you simplify your generated "where" to just (o => o is
ProfileCircular) - for me at least the analogous code throws another
unobvious exception. It seems that error reporting for that case isn't
particularly good, but otherwise, I can understand why it cannot
handle it.

In any case, if you do queries on DLINQ entities, rather than domain
objects, the problem goes away, so it is what I advise you to do. You
can still have your domain objects, just do the mapping after you've
done all the filtering, and make sure to realize the query by using
AsEnumerable on the IQueryable that you have so that DLINQ doesn't
kick in. Or, perhaps, don't bother with domain objects at all - just
use the entity classes directly. In practice, it is often the best
option.

 
Reply With Quote
 
Ben Voigt [C++ MVP]
Guest
Posts: n/a
 
      19th Mar 2009
Fritz wrote:
> "Pavel Minaev" wrote:
>>
>> Please clarify what flavor of LINQ you're using (to objects, SQL, EF
>> etc). Also, can you include the value returned by ToString() for the
>> expression tree that you've built (it's hard to read it the way it's
>> spelt out in your post, and it omits actual values in the nodes)?
>>
>>

>
> Hi Pavel
>
> The expression tree in literal is:
>
> Lambda - e => IIF((e Is ProfileCircular), (Convert((e As
> ProfileCircular).Diameter) >= 40), True)
> Conditional - IIF((e Is ProfileCircular), (Convert((e As
> ProfileCircular).Diameter) >= 40), True)
> TypeIs - (e Is ProfileCircular)
> Parameter - e
> GreaterThanOrEqual - (Convert((e As ProfileCircular).Diameter)
> >= 40) Convert - Convert((e As ProfileCircular).Diameter)

> MemberAccess - (e As ProfileCircular).Diameter
> TypeAs - (e As ProfileCircular)
> Parameter - e
> Constant - 40
> Constant - True


The problem is that the IIF function doesn't short-circuit like AND would.

Not to mention that the else-part of the IIF needs to be FALSE!


 
Reply With Quote
 
Pavel Minaev
Guest
Posts: n/a
 
      20th Mar 2009
On Mar 19, 3:12*pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote:
> Fritz wrote:
> > "Pavel Minaev" wrote:

>
> >> Please clarify what flavor of LINQ you're using (to objects, SQL, EF
> >> etc). Also, can you include the value returned by ToString() for the
> >> expression tree that you've built (it's hard to read it the way it's
> >> spelt out in your post, and it omits actual values in the nodes)?

>
> > Hi Pavel

>
> > The expression tree in literal is:

>
> > Lambda *- *e => IIF((e Is ProfileCircular), (Convert((e As
> > ProfileCircular).Diameter) >= 40), True)
> > * Conditional *- *IIF((e Is ProfileCircular), (Convert((e As
> > ProfileCircular).Diameter) >= 40), True)
> > * * *TypeIs *- *(e Is ProfileCircular)
> > * * * * Parameter *- *e
> > * * *GreaterThanOrEqual *- *(Convert((e As ProfileCircular).Diameter)
> > * * * * >= 40) Convert *- *Convert((e As ProfileCircular)..Diameter)
> > * * * * * *MemberAccess *- *(e As ProfileCircular).Diameter
> > * * * * * * * TypeAs *- *(e As ProfileCircular)
> > * * * * * * * * *Parameter *- *e
> > * * * * Constant *- *40
> > * * *Constant *- *True

>
> The problem is that the IIF function doesn't short-circuit like AND would..


What IIF function? This isn't VB code snippet, this is just the result
of applying ToString to a lambda expression. IIF in that case is a
basic operator, not a function - C# ?: ternary operator is translated
to IIF, and that one is quite obviously short-circuited (though in
practice, when dealing with IQueryable, it is of course up to the
implementer how to handle that).

 
Reply With Quote
 
Ben Voigt [C++ MVP]
Guest
Posts: n/a
 
      20th Mar 2009


"Pavel Minaev" <(E-Mail Removed)> wrote in message
news:57571c40-6f10-4266-9563-(E-Mail Removed)...
> On Mar 19, 3:12 pm, "Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote:
>> Fritz wrote:
>> > "Pavel Minaev" wrote:

>>
>> >> Please clarify what flavor of LINQ you're using (to objects, SQL, EF
>> >> etc). Also, can you include the value returned by ToString() for the
>> >> expression tree that you've built (it's hard to read it the way it's
>> >> spelt out in your post, and it omits actual values in the nodes)?

>>
>> > Hi Pavel

>>
>> > The expression tree in literal is:

>>
>> > Lambda - e => IIF((e Is ProfileCircular), (Convert((e As
>> > ProfileCircular).Diameter) >= 40), True)
>> > Conditional - IIF((e Is ProfileCircular), (Convert((e As
>> > ProfileCircular).Diameter) >= 40), True)
>> > TypeIs - (e Is ProfileCircular)
>> > Parameter - e
>> > GreaterThanOrEqual - (Convert((e As ProfileCircular).Diameter)
>> > >= 40) Convert - Convert((e As ProfileCircular).Diameter)
>> > MemberAccess - (e As ProfileCircular).Diameter
>> > TypeAs - (e As ProfileCircular)
>> > Parameter - e
>> > Constant - 40
>> > Constant - True

>>
>> The problem is that the IIF function doesn't short-circuit like AND
>> would.

>
> What IIF function? This isn't VB code snippet, this is just the result
> of applying ToString to a lambda expression. IIF in that case is a
> basic operator, not a function - C# ?: ternary operator is translated
> to IIF, and that one is quite obviously short-circuited (though in
> practice, when dealing with IQueryable, it is of course up to the
> implementer how to handle that).


I had assumed, apparently mistakenly, that it was showing the SQL generated
by LINQ-to-SQL.

And translating ?: to IIF is an obvious error, because they don't have the
same semantics.

In any case, the else-part argument is clearly wrong (shown as true but
should be false).

 
Reply With Quote
 
Pavel Minaev
Guest
Posts: n/a
 
      20th Mar 2009
On Mar 20, 10:19*am, "Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote:
> I had assumed, apparently mistakenly, that it was showing the SQL generated
> by LINQ-to-SQL.


Yep, it's not (since at that point the given instance of Expression<T>
doesn't know that it's going to be passed to an IQueryable
implementation provided by LINQ to SQL).

It's really just a handy condensed representation of the expression
tree, mostly for debugging purposes. For some reason, they've decided
it to be "language agnostic" in that it looks unlike any present .NET
language.

> In any case, the else-part argument is clearly wrong (shown as true but
> should be false).


I don't think it's relevant to the problem Fritz was having. I did my
repro on a new solution that did not include any of its code, only
following the descriptions instead.
 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Using Existing Classes in Entity Framework Gregory A. Beamer Microsoft ADO .NET 0 27th Oct 2009 02:32 PM
Derived dblinq entity class without creating constructor Andrus Microsoft C# .NET 1 10th Nov 2007 09:22 PM
generate entity classes butch77@web.de Microsoft C# .NET 3 9th Oct 2007 03:23 PM
Newbie on Inheritance, Base classes and derived classes aaj Microsoft C# .NET 2 21st Jun 2005 03:52 PM
Custom Entity classes are killing me. Tom B Microsoft Dot NET Framework 4 21st May 2005 04:08 AM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 08:47 AM.