Laden...

Linq to sql: complexe Suche

Erstellt von T-Man vor 13 Jahren Letzter Beitrag vor 13 Jahren 1.038 Views
T
T-Man Themenstarter:in
210 Beiträge seit 2006
vor 13 Jahren
Linq to sql: complexe Suche

verwendetes Datenbanksystem: MSSQL

Moin!

Hier zunächst die wichtigsten Klassen aufs wesentliche reduziert:


    public abstract class DataValue
    {
        [Column(IsPrimaryKey = true)]
        public Guid Id { get; internal set; }

        [Column(IsDiscriminator = true)]
        private string Class;

        [Column]
        public Guid? MetadataId { get; internal set; }
        private EntityRef<Bracket> _Metadata;
        [DataMember]
        [Association(ThisKey = "MetadataId", OtherKey = "Id")]
        internal Bracket Metadata { get { return _Metadata.Entity; } set { _Metadata.Entity = value; } }

        internal virtual IQueryable FindEqualInList([NotNull]IQueryable list)
        {
            return list.Cast<DataValue>().Where(dv => dv.MetadataId == MetadataId || dv.MetadataId == null && MetadataId == null);
        }
    }

    public class BoolValue : SimpleValue
    {
        [Column(CanBeNull = true)]
        private bool? boolValue;

        internal override IQueryable FindEqualInList(IQueryable list)
        {
            return base.FindEqualInList(list.OfType<BoolValue>().Where(bv => bv.boolValue == null && boolValue == null || bv.boolValue == boolValue));
        }
    }

    public class Bracket : DataValue
    {
        [Association(OtherKey = "SourceItemId")]
        internal EntitySet<ValueAssign> _BracketValues = new EntitySet<ValueAssign>();

        internal override IQueryable FindEqualInList(IQueryable list)
        {
            return base.FindEqualInList(list.OfType<Bracket>()).Cast<Bracket>().Where(sv => sv._BracketValues.Count() == _BracketValues.Count).ToList().FindAll(sv =>
                sv._BracketValues.All(va1 => _BracketValues.FirstOrDefault(va2 =>
                    va2.Ordinal == va1.Ordinal && va2.DestinationItemId == va1.DestinationItemId) != null)).AsQueryable();
        }
    }

    public class ValueAssign
    {
        [Column(IsPrimaryKey = true)]
        internal Guid SourceItemId { get; set; }

        [Column]
        public Guid DestinationItemId { get; internal set; }

        [Column(IsPrimaryKey = true)]
        public int Ordinal { get; internal set; }

        private EntityRef<DataValue> _DestinationItem;
        [Association(ThisKey = "DestinationItemId", OtherKey = "Id")]
        public DataValue DestinationItem
        {
            get { return _DestinationItem.Entity; }
            set { _DestinationItem.Entity = value; }
        }
    }

Wenn ein neuer DataValue gespeichert werden soll, rufe ich für diesen zunächst FindEqualInList() mit der Tabelle als Parameter auf um zu sehen, ob es schon einen identischen Wert gibt... Das funktioniert auch wunderbar. Leider verlasse ich in dem FindEqualInList in der Klasse Bracket den DataBase-Context in dem Moment in dem ich das ToList() aufrufe. Hier werden alle in Frage kommenden Brackets aus der DB geladen und dann wird die Liste weiter eingeschränkt. Ich mache das ToList().FindAll(), da ein Where nicht funktioniert, da die weitere Lambda-Expression nicht in SQL übersetzt werden kann.

Nun meine Frage: (Wie) kann ich die Lambda-Expression so umwandeln, dass sie in SQL übersetzbar ist? Das würde das Laden in den Speicher verhindern und sicher wesentlich schneller laufen.

Vielen Dank schon mal in voraus.
T-Man

S
902 Beiträge seit 2007
vor 13 Jahren

Hallo,

in dem du ExpressionTrees verwendest.

EIn beispiel:


Expression<Func<string, bool>> exp = (s) => s.Length > 1;

mfg
serial

T
T-Man Themenstarter:in
210 Beiträge seit 2006
vor 13 Jahren

Danke für den Tipp, er führt mich schon etwas weiter. Leider noch nicht zum Ziel.

ExpressionTrees verstehe ich jetzt ungefähr. Für einfachere Abfragen könnte ich auch einen aufstellen.

Hier müsste ich ja sowas wie

Where(sv => sv._BracketValues[0].DestinationItemId == _BracketValues[0].DestinationItemId && 
sv._BracketValues[1].DestinationItemId == _BracketValues[1].DestinationItemId && ...)

dynamisch erstellen.

Aber wie referenziere ich die einzelnen Elemente von _BracketValues um sie zu vergleichen? Der Indexer und ElementAt sind nicht in SQL übersetzbar, sprich, mein Beispiel funktioniert nicht.

Kann mir da jemand einen weiteren Tipp geben?

Danke!
T-Man

W
955 Beiträge seit 2010
vor 13 Jahren

OT:
@T-Man: wo hast Du das NotNullAttribute her? Habe ich was verpaßt oder ist das eine Eigenkreation?

T
T-Man Themenstarter:in
210 Beiträge seit 2006
vor 13 Jahren

OT:
@T-Man: wo hast Du das NotNullAttribute her? Habe ich was verpaßt oder ist das eine Eigenkreation? Von ReSharper. Das hätte ich hier weglassen können...

T
T-Man Themenstarter:in
210 Beiträge seit 2006
vor 13 Jahren

Ich weiß jetzt wie es theoretisch geht.
Da ich nur herausfinden sollte, ob es geht kann ich hier nicht die konkrete Lösung präsentieren.

Gruß
T-Man

2.891 Beiträge seit 2004
vor 13 Jahren

Eine kleine Expression-Bastelei findest du z.B. unter [ExtensionMethods] LeftOuterJoin für IQueryable (und IEnumerable)