从Entity Framework中获取多对多关系的结果列表

时间:2017-11-02 16:34:10

标签: c# entity-framework linq ef-database-first

我使用数据库优先方法Entity Framework many-to-many relation

我的课程是:

class User
{
    public int UserId {get; set;}

    // every User has zero or more Products :
    public virtual ICollection<Product> Products {get; set;}

    ... //  other properties
}

class Product
{
    public int ProductId {get; set;}

    // every Product belongs to zero or more Users:
    public virtual ICollection<User> Users {get; set;}

    ... //  other properties
}

class MyDbContext : DbContext
{
    public DbSet<User> Users {get; set;}
    public DbSet<Product> Products {get; set;}
} 

我在列表lstProductIds中有一个productIds列表。我需要使用linq

找出用户及其产品的列表

如果是SQL,我会做这样的事情。

var str = String.Join(",", lstProductIds);
str = str.Replace(",", "','"); 

var conn = new SqlConnection(cs);
conn.Open();
var cmd = new SqlCommand("SELECT a.UserId,b.ProductId FROM Users a JOIN Product b on a.UserId = b.UserId WHERE ProductId onId IN ('" + str + "')", conn);
SqlDataReader rdr = cmd.ExecuteReader();

while (rdr.Read())
{
     UserDetails.Add(new UserProduct { OrganizationId = Convert.ToString(rdr["UserId "]), ProductId= Convert.ToString(rdr["ProductId"]) });
}

conn.Close();

所以我得到了一个用户ID和ProductId的列表。

我在linq中尝试了类似的东西,但这最终只给了我一个userId每个产品。

var UserDetails = db.Products.Where(o => lstProductIds.Contains(o.ProductID.ToString()))
                             .Select(o => new UserProduct 
                                              { ProductId = o.ID.ToString(), 
                                                UserId = o.Users.Select(a => a.UserId.ToString()).FirstOrDefault()
                                              })
                             .ToList();

我知道FirstOrDefault()是问题所在,它只为产品选择一个用户,但如何更改它以吸引所有用户?

3 个答案:

答案 0 :(得分:3)

这是SelectMany(或其LINQ等效项)的工作。

例如

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;

namespace Ef6Test
{


    class User
    {
        public int UserId { get; set; }

        // every User has zero or more Products :
        public virtual ICollection<Product> Products { get; } = new HashSet<Product>();


}

    class Product
    {
        public int ProductId { get; set; }

        // every Product belongs to zero or more Users:
        public virtual ICollection<User> Users { get; } = new HashSet<User>();


    }

    class Db : DbContext
    {
        public DbSet<User> Users { get; set; }
        public DbSet<Product> Products { get; set; }
    }




    class Program
    {
        static void Main(string[] args)
        {

            Database.SetInitializer(new DropCreateDatabaseAlways<Db>());

            using (var db = new Db())
            {

                db.Database.Log = m => Console.WriteLine(m);
                db.Database.Initialize(true);

                var lstProductIds = new List<int>() { 1, 2, 3 };

                var q = from p in db.Products
                        where lstProductIds.Contains(p.ProductId)
                        from u in p.Users
                        select new { p.ProductId, u.UserId };

                var UserDetails = q.ToList();
            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}

答案 1 :(得分:1)

正如@David指出的那样,你需要使用SelectMany来获得你想要的结果。

有些事情就是这样:

UserDetails = db.Products.Where(o => lstProductIds.Contains(o.ProductID.ToString()))
             .SelectMany(o => o.Users.Select(u => new { o, u })) 
             .Select(s => new UserProduct {ProductId = s.o.ProductId.ToString(), 
              UserId =s.u.UserId.ToString()}).ToList();

答案 2 :(得分:0)

您可以在EF中使用联接。据我所知,您希望检索具有某些产品列表的用户的所有产品(lstProductIds)。代码未经过测试,您可能需要解决内部和外部密钥问题,但您可能正在寻找以下内容:

db.Users.Join(db.Products.Join(lstProductIds, x => x.ProductId, y => y.ProductId, (x, y) => x), x => x.UserId, y => y.UserId, (x, y) => x).Include(x => x.Products).ToList();