Frage

Mit NHibernate Ich versuche, eine Liste von B zu bekommen zu erhalten, in dem eine IList Eigenschaft von B eine bestimmte Instanz von A enthält.

Der folgende Code sollte hoffentlich die Situation erklären deutlicher:

public void test()
{
    A a1 = new A();
    A a2 = new A();
    B b1 = new B();
    b1.As = new List<A> { a1 };
    // ...database save cut...

    using (ISession session = SessionFactory.OpenSession())
    {
        var result1 = session.CreateCriteria<B>()
            .CreateAlias("As", "a_As")
            .Add(Restrictions.Eq("a_As.ID", a1.ID))
            .List();

        var result2 = session.CreateCriteria<B>()
            .CreateAlias("As", "a_As")
            .Add(Restrictions.Eq("a_As", a1))
            .List();
    }
}

class A
{
    public virtual int ID { get; set; }
}

class B
{
    public virtual IList<A> As { get;set;}
}

Die zweite Abfrage schlägt mit dem Fehler: could not resolve property: a_As of: B

Wie kann ich führe diese Abfrage mit Objektinstanzen, ohne die ID-Eigenschaften explizit mit wie in der ersten Abfrage oben.

Edit: Um auf diesem zu erweitern, ich habe eine generische Klasse, die NHibernate Operationen mit meinen Einheiten führt. Ich habe gerade eine „IsReferenced“ Methode erstellt, die wie folgt beginnt:

public bool IsReferenced(T entity)
{
    // Get the types (and their properties) that reference the type in question
    var typeProps = from type in typeof(T).Assembly.GetTypes()
                    let props = type.GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => p.Name)
                    let collections = type.GetProperties().Where(p => typeof(IEnumerable<T>).IsAssignableFrom(p.PropertyType)).Select(p => p.Name)
                    where type.IsClass && !type.IsAbstract && ((props != null && props.Count() > 0) || (collections != null && collections.Count() > 0))
                    select new { EntityType = type, Properties = props, Collections = collections };

    var multiCriteria = NHibernateSession.CreateMultiCriteria();
    foreach (var typeProp in typeProps)
    {
        var criteria = NHibernateSession.CreateCriteria(typeProp.EntityType);
        var disjunction = new Disjunction();
        foreach (var propName in typeProp.Properties)
        {
            disjunction.Add(Restrictions.Eq(propName, entity));
        }
        foreach (var collectionName in typeProp.Collections)
        {
            throw new NotImplementedException();
        }
        criteria.Add(disjunction);
        multiCriteria.Add(criteria);
    }
.....
}

Ich verwende typeProps ein mehrkriteriellen zu bauen alle Entitäten zu finden überall dort, wo Referenz die angegebene. Es funktioniert gut für den normalen Eigenschaften, aber Sammlung Eigenschaften geben mir Kummer. Ich bin mir nicht sicher, wie zu gehen, um die Einschränkung in die Kriterien hinzugefügt wird.

War es hilfreich?

Lösung 2

Ich habe eine Lösung gefunden, die angezeigt wird, um Arbeit für alle meine aktuellen Einheiten, basierend auf zwei Stücke von Informationen, die ich habe überflogen während der Arbeit an diesem:

  • Die Dokumentation besagt, dass Kleinbuchstaben ‚id‘ ist eine spezielle Eigenschaft, die verwendet werden können, die ID von jedem Unternehmen zu verweisen.
  • ISession macht eine öffentliche Methode object ISession.GetIdentifier(object obj)

Diese beiden titbits lassen Sie uns etwas tun, wie folgt aus:

var result2 = session.CreateCriteria<B>()
        .CreateAlias("As", "a_As")
        .Add(Restrictions.Eq("a_As.id", session.GetIdentifier(a1)))
        .List();

Und die daraus resultierenden IsReferenced Methode sieht wie folgt aus:

    public bool IsReferenced(T entity)
    {
        // Get the types (and their properties) that reference the type in question
        var typeProps = from type in typeof(T).Assembly.GetTypes()
                        let props = type.GetProperties().Where(p => p.PropertyType == typeof(T)).Select(p => p.Name)
                        let collections = type.GetProperties().Where(p => typeof(IEnumerable<T>).IsAssignableFrom(p.PropertyType)).Select(p => p.Name)
                        where type.IsClass && !type.IsAbstract && ((props != null && props.Count() > 0) || (collections != null && collections.Count() > 0))
                        select new { EntityType = type, Properties = props, Collections = collections };

        var multiCriteria = NHibernateSession.CreateMultiCriteria();

        // Create a big or query to test whether any of the properties are, or contain, the entity parameter
        foreach (var typeProp in typeProps)
        {
            var criteria = NHibernateSession.CreateCriteria(typeProp.EntityType);
            var disjunction = new Disjunction();
            foreach (var propName in typeProp.Properties)
            {
                disjunction.Add(Restrictions.Eq(propName, entity));
            }
            foreach (var collectionName in typeProp.Collections)
            {
                string alias = string.Format("a_{0}", collectionName);
                criteria.CreateAlias(collectionName, alias, NHibernate.SqlCommand.JoinType.LeftOuterJoin);

                disjunction.Add(Restrictions.Eq(string.Format("{0}.id", alias), NHibernateSession.GetIdentifier(entity)));
            }
            criteria.Add(disjunction);
            multiCriteria.Add(criteria);
        }

        var results = multiCriteria.List();

        bool hasReferences = false;
        foreach (var resultSet in results)
        {
            if ((resultSet as System.Collections.IList).Count != 0)
            {
                hasReferences = true;
                break;
            }
        }
        return hasReferences;
    }

Wenn nur mein Gehirn getreten, bevor ich die Hälfte meines Rufes als Prämie setzen ...

Andere Tipps

Diese Art der Abfrage ist besser gedient HQL als Kriterien:

session.CreateQuery("from B b where :a in elements(b.As)")
       .SetParameter("a", a1)
       .List();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top