获取Entity Framework中多对多关系的结果列表
To obtain a result list from many to many relationship in Entity Framework
我有一个 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
中有一个 productId 列表。我需要使用 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()
是问题所在,它只是为该产品选择了一个用户,但我该如何更改它才能获得所有用户?
您可以在 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();
这是 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();
}
}
}
正如@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();
我有一个 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
中有一个 productId 列表。我需要使用 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()
是问题所在,它只是为该产品选择了一个用户,但我该如何更改它才能获得所有用户?
您可以在 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();
这是 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();
}
}
}
正如@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();