开发者

LINQ to Entities projection of nested list

开发者 https://www.devze.com 2023-01-01 04:57 出处:网络
Assuming these objects... class MyClass { int ID {get;set;} string Name {get;set;} List<MyOtherClass> Things {get;set;}

Assuming these objects...

class MyClass
{
     int ID {get;set;}
     string Name {get;set;}
     List<MyOtherClass> Things {get;set;}
}

class MyOtherClass
{
     int ID {get;set;}
     string Value {get;set;}
}

How do I perform a LINQ to Entities Query, using a projection like below, that will give me a List? This works fine with an IEnumerable (assuming MyClass.Things is an IEnumerable, but I need to use List)

MyClass myClass = (from MyClassTable mct in this.Context.MyClassTableSet
                        select new MyClass
                        {
                             ID = mct.ID,
                             Name = mct.Name,
                             Things = (from MyOtherClass moc in mct.Stuff
                                       where moc.IsActive
                                       select new MyOtherClass
                                       {
                                            ID = moc.ID,
                                            Value = moc.Value
                                       }).AsEnumerable()
                        })开发者_运维问答.FirstOrDefault();

Thanks in advance for the help!


You don't. You have to do this part in L2O.

So you could do:

var q = (from MyClassTable mct in this.Context.MyClassTableSet
         select new // note anonymous type; important!
         {
             ID = mct.ID,
             Name = mct.Name,
             Things = (from MyOtherClass moc in mct.Stuff
                       where moc.IsActive
                       select new MyOtherClass
                       {
                           ID = moc.ID,
                           Value = moc.Value
                       }
          }).AsEnumerable();

MyClass myClass = (from mct in q
                   select new MyClass
                   {                 
                       ID = mct.ID,
                       Name = mct.Name,
                       Things = mct.Things.ToList()
                   }).FirstOrDefault();

There's no way to do this in one query.


I'm not sure what exactly your asking about, but List<T> does implement IEnumerable<T> (which is just an interface for an enumerable sequence).

A code that will do your projection and have Things be a List instead of an IEnumerable would use the ToList() operator, which creates a List<T> from any IEnumerable<T> this:

MyClass myClass = (from MyClassTable mct in this.Context.MyClassTableSet
                        select new MyClass
                        {
                             ID = mct.ID,
                             Name = mct.Name,
                             Things = (from MyOtherClass moc in mct.Stuff
                                       where moc.IsActive
                                       select new MyOtherClass
                                       {
                                            ID = moc.ID,
                                            Value = moc.Value
                                       }).ToList()
                        }).FirstOrDefault();


Please look at following solution. You can separate fields for List and IEnumerable in your class:

class MyClass
{
    ...

    List<MyOtherClass> m_Things = new List<MyOtherClass>();
    public List<MyOtherClass> Things
    {
        get
        {
            if (ThingsForLinq != null)
            {
                m_Things = ThingsForLinq.ToList();
                ThingsForLinq = null;
            }
            return m_Things;
        }
        set
        {
            m_Things = value;
        }
    }

    public IEnumerable<MyOtherClass> ThingsForLinq { get; set; }
}

So you have to use ThingsForLinq in EF Linq queries:

MyClass myClass = (from MyClassTable mct in this.Context.MyClassTableSet
                    select new MyClass
                    {
                         ID = mct.ID,
                         Name = mct.Name,
                         ThingsForLinq = (from MyOtherClass moc in mct.Stuff
                                   where moc.IsActive
                                   select new MyOtherClass
                                   {
                                        ID = moc.ID,
                                        Value = moc.Value
                                   }).AsEnumerable()
                    }).FirstOrDefault();

And use Things later:

myClass.Things.Add(...)


This answer was helpful, but this is how I do this. This converts to POCOs, and can supported unlimited nested lists. Very simple but powerful:

Product product = new Product();
List<CoverageCondition> covCondList = null;
CoverageCondition covCond = null;
Question question = null;
List<Question> questList = null;

var prod = db.PRODUCTs.Include("COVERAGE_CONDITION.QUESTIONs").Where(p => p.PRODUCT_CODE == productCode).FirstOrDefault();

product.ProductId = prod.PRODUCT_ID;
product.ProductCode = prod.PRODUCT_CODE;
product.ProductName = prod.PRODUCT_NAME;

// go through coverage conditions
covCondList = new List<CoverageCondition>();
product.CoverageConditions = covCondList;
foreach (COVERAGE_CONDITION cc in prod.COVERAGE_CONDITION)
{
    covCond = new CoverageCondition();
    covCond.ConditionId = cc.COV_CONDITION_ID;
    covCond.ConditionCode = cc.COV_CONDITION_CODE;
    covCond.ConditionName = cc.COV_CONDITION_NAME;
    covCondList.Add(covCond);

    // go through questions for each coverage condtion, if any
    questList = new List<Question>();
    covCond.Questions = questList;
    foreach (QUESTION q in cc.QUESTIONs)
    {
        question = new Question();
        question.QuestionId = q.QUESTION_ID;
        question.QuestionCode = q.QUESTION_CODE;
        question.QuestionText = q.QUESTION_TEXT;
        questList.Add(question);
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消