【问题标题】:Many to Many SQL query in EntityFramework实体框架中的多对多 SQL 查询
【发布时间】:2010-12-18 06:24:49
【问题描述】:

我需要一些关于 sql 查询的帮助,为此我使用 EntityFramework 作为 ORM。

我有一个用户--组多对多关系,即一个用户可以属于多个组,一个组可以有多个用户。

我做映射的方式是..

USER tbl、Usr_Grp 表和组表,其中 PK = 主键,FK = 外键

USER 表有 --> UserId(PK) , UserName
组表有 --> GroupId (PK), GroupName
Usr_Grp 表有 --> Id(PK), UUserId(FK to usertable), GGroupId (FK to GroupTable)

我面临的问题是......在我的 api 中,我将获得一组 GroupId,我想只找到属于所有这些 GroupId 的那些用户(即传入的所有组) )。

有没有办法在实体框架或Sql中编写这个查询。在这方面我能得到任何帮助,我将不胜感激。

-RN

【问题讨论】:

  • 我对 Entity Framework 不是很熟悉,但是我执行的 sql 查询对我有帮助吗?
  • 是的,这肯定会有所帮助。
  • @adatapost 这个问题有点不同,我有一组用户必须属于的角色。我没有遇到 EF 问题,我可以弄清楚,但我无法获得正确的 SQL 查询。

标签: c# sql entity-framework


【解决方案1】:

联结表 Usr_Grp 不应该有 Id。如果您在 (UUserId, GGroupId) 上创建复杂的主键,那么 EF 会自动理解它是多对多关系。

如果你的关系如下:

然后EF会生成多对多关系的实体:

设置完所有内容后,您可以轻松使用此类代码:

var ids = new List<int>{1, 2, 3, 4}; // GroupIds you need
context.Groups
        .Where(x=> ids.Contains(x.Id))
        .SelectMany(x=>x.Users)
        .Distinct()
        .ToArray();

如果您无法更改模型,则只需使用这样的 linq 查询:

context.Grp_Usrs
        .Where(x=> ids.Contains(x.GroupId))
        .SelectMany(x=>x.Users)
        .Distinct()
        .ToArray();

【讨论】:

  • 是不是可以简单的去掉Usr_Grp实体,然后用它在两张表之间形成多对多关系,去掉Id列?我知道如果你只是将表格拖到设计器上,EF不会这样做,但你不能手动这样做吗?
  • @Kirk Broadhurst - 从未尝试过这样做。我不喜欢手动编辑 edmx 文件。我想这是不可能的,但那不是什么,而是我的感受。我真的可能是错的。您可以在 stackoverflow 上将其作为单独的问题提出,切割者可以回答。
  • @ Ben - 如果您无法更改模型,请参阅答案的最后几行。它不像多对多关系那样清晰,但它应该可以工作。
  • 我不建议编辑edmx,只是在设计器上右击,在两个表之间添加新的关系。
【解决方案2】:

试试这个方法:

var gid = new List<int> {1, 2, 3, 4};
var users_id = entity.Usr_Grp.where(x=> gid.Contains(x.uid);

希望对你有帮助!

【讨论】:

    【解决方案3】:
        //Here is a LinqToSql example but it should work with EF too.Taking into consideration your mappings I would have the following approach in handling a many to many relationship:
    
        //1. First You need to save you records into the tables as many to many relationship
        [Test]
        public void CanSaveGroupUsers()
        {
            var group = Group { CreatedDate = DateTime.UtcNow, Name = "The Rookies" };
            var groupId = _groupRepository.SaveGroup(group);
    
            var user = new User { CreatedDate = DateTime.Now, Name = "Justin Bieber" };
            var userId = _userRepository.SaveUser(user);
    
            var userGroup = new UserGroup { GroupId = groupId, UserId = userId };
            _group.SaveUserGroup(userGroup);
        }
    
        //2. Then you can retrive them this way:
        [Test]
        public void CanGetGroupUsers()
        {
            var groupIds = new List<int>{1,2,3,4};
            var users = _usersRepository.GetAllUsers();
            var specificUsersList = (users.AsQueryable().Where(user => groupIds.Contains(user.UserGroups.FirstOrDefault().GroupId)));
        }
    
        //3. I attached my repository code just in case
        public IQueryable<User> GetAllUsers()
        {
            _db.ObjectTrackingEnabled = false;
            return _db.Users;
        }
        public int SaveGroup(Group Group)
        {
            var dbGroup = new Group
            {
                Name = Group.Name,
                CreatedDate = Group.CreatedDate
            };
            _db.Groups.InsertOnSubmit(dbGroup);
            _db.SubmitChanges();
            return dbGroup.Id;
        }
    
        public int SavUser(User user)
        {
            var dbUser = new User
            {
                CreatedDate = user.CreatedDate,
                Name = user.Name
            };
            _db.Users.InsertOnSubmit(dbUser);
            _db.SubmitChanges();
            return dbUser.UserId;
        }
    
         public void SaveUserGroup(UserGroup userGroup)
        {
            var dbUserGroup = new UserGroup
            {
                GroupId = userGroup.GroupId,
                UserId = userGroup.UserId
    
            };
            _db.UserGroups.InsertOnSubmit(dbUserGroup);
            _db.SubmitChanges();
        }
    
        //Hope this helps:)
    

    【讨论】:

    • EntityFramework 将把 UserGroup 表抽象成一个纯粹的关系——所以User 有一个Groups 属性,而Group 有一个Users 属性。 UserGroup 表根本不会作为实体出现在生成的命名空间中。
    • 感谢您指出这一点。我通常使用 NHibernate,你也不需要第三个表(GroupUsers),因为你可以指定多映射,你只需要用户和组实体。看来我是时候从 LinqToSql 转移到 EF 了 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-13
    • 2016-12-15
    相关资源
    最近更新 更多