实体框架代码首先有多个自定义用户和映射表

时间:2022-10-05 15:28:04

I am working with WebAPI, EF Code First and have a problem concerning many-to-many relationships:

我正在使用WebAPI,EF Code First,并且遇到有关多对多关系的问题:

I am working with a custom user inherited from "IdentityUser" who can have many Projects.

我正在使用从“IdentityUser”继承的自定义用户,该用户可以拥有许多项目。

These Projects can now have multiple users. In Addition to this I want to store additional fields in a mapping table.

这些项目现在可以拥有多个用户。除此之外,我想在映射表中存储其他字段。

public class MyCustomUser : IdentityUser
{

    // blah blah...

    public virtual ICollection<Project> Projects { get; set; }
}

public class Project
{
    public int Id { get; set; }
    public string Title { get; set; }

    public virtual ICollection<MyCustomUser> Users { get; set; }
}

public class Users2Projects
{
    public int UserId { get; set; }
    public int ProjectId { get; set; }

    public virtual MyCustomUser User { get; set; }
    public virtual Project Project { get; set; }

    public string AdditionalField1 {get;set;}
    public string AdditionalField1 {get;set;}
}

The question is: How do I have to set the relations (FluentAPI) to insert a Project for a User which is already there? Because the user can use the application no matter if he has a Project or not.

问题是:我如何设置关系(FluentAPI)为已经存在的用户插入项目?因为用户可以使用该应用程序,无论他是否有项目。

So the User CAN have a Project, but a Project has to have at least one User. I am getting the User through the Owin "UserManager" "FindById" which returns "MyCustomUser". Creating a new Users2Project-Class, adding the new Project to it, adding the user to it fails because EF wants to store a new User. How can I solve this?

因此,用户可以有一个项目,但项目必须至少有一个用户。我通过Owin“UserManager”“FindById”获取用户,返回“MyCustomUser”。创建新的Users2Project-Class,向其添加新项目,将用户添加到其中失败,因为EF想要存储新用户。我怎么解决这个问题?

Kind Regards

2 个解决方案

#1


You don't need to set anything with FluentAPI when you explicitly declare your many-to-many relationship entity. But you should remove the following lines from User and Project, respectively:

当您明确声明多对多关系实体时,不需要使用FluentAPI设置任何内容。但是你应该分别从User和Project中删除以下行:

public virtual ICollection<Project> Projects { get; set; }

public virtual ICollection Projects {get;组; }

public virtual ICollection<MyCustomUser> Users { get; set; }

public virtual ICollection Users {get;组; }

and add on both entities:

并添加两个实体:

public virtual ICollection<Users2Projects> Users2Projects { get; set; }

public virtual ICollection Users2Projects {get;组; }

To add a new Project for an existing User you can:

要为现有用户添加新项目,您可以:

var relation = new Users2Projects() {
    User = existingUser, // reference retrieved from Context.
    Project = new Project() { Title = "Project Alpha" }
}

Context.Users2Projects.Add(relation);
Context.SaveChanges();

As far as I know, it is not possible to force the Project to have at least one User using a explicit relationship class on Entity Framework, so you would have to check that programmatically upon inserting a Project into the Context:

据我所知,不可能强制项目至少有一个用户在Entity Framework上使用显式关系类,因此在将项目插入Context时必须以编程方式检查:

if (project.Users2Projects.Count() == 0)
    throw new Exception("Project must have at least one user.")

Context.Projects.Add(project);
Context.SaveChanges();

and upon deleting an User you do the check before:

删除用户后,您可以进行以下检查:

var projectsToDelete = new List<Project>();

foreach (var relationship in user.Users2Projects)
{
    if (relationship.Project.Users2Projects.Count() <= 1)
        projectsToDelete.Add(relationship.Project);
}

Context.MyCustomUsers.Remove(user);
Context.Projects.RemoveRange(projectsToDelete);
Context.SaveChanges();

#2


You are clearly missing a conceptual entity here although you actually already modeled it a bit as your Users2Projects mapping table. You may want to untangle a few concepts around the bounded contexts that exist in your application, and look again at your requirements

虽然你实际上已经将它作为Users2Projects映射表进行了一些建模,但你显然在这里缺少一个概念实体。您可能想要围绕应用程序中存在的有界上下文解开几个概念,并再次查看您的要求

  1. User administration (i.e. administration of users that are allowed to access your system) seems to be a different concern than project administration:

    用户管理(即允许访问系统的用户的管理)似乎与项目管理不同:

    Because the user can use the application no matter if he has a Project or not.

    因为用户可以使用该应用程序,无论他是否有项目。

  2. In project administration, for the assignment of a user to a project, it appears there is additional information specific to the project that needs to be captured as part of the ProjectMemberAssignment. Your Project appears to be the aggregate root for this bounded context, and should be made responsible for managing it's member assignments:

    在项目管理中,为了将用户分配给项目,似乎有一些特定于项目的附加信息需要作为ProjectMemberAssignment的一部分被捕获。您的项目似乎是此有界上下文的聚合根,应该负责管理它的成员分配:

    public class Project
    {
        public virtual int Id { get; private set; }
        public string Title { get; set; }
    
        public void AssignMember(int userId, string someField, string someOtherField)
        {
            if (MemberAssignments.Any(x => x.UserId == userId))
                throw new InvalidOperationException("User already assigned");
            MemberAssignments.Add(new ProjectMemberAssignment(Id, userId, someField, someOtherField));
        }
    
        // Other behavior methods.
    
        public virtual ICollection<ProjectMemberAssignment> MemberAssignments 
        { 
            get;
            set; 
        } 
    }
    

Note that you can get the projects for a user using a simple query, without the need to maintain a many-to-many relationship in your model:

请注意,您可以使用简单查询为用户获取项目,而无需在模型中维护多对多关系:

var user = ...;
var projectsForUser =
    from project in db.Projects
    where project.MemberAssignments.Any(x => x.userId == user.UserId)
    select project;    

#1


You don't need to set anything with FluentAPI when you explicitly declare your many-to-many relationship entity. But you should remove the following lines from User and Project, respectively:

当您明确声明多对多关系实体时,不需要使用FluentAPI设置任何内容。但是你应该分别从User和Project中删除以下行:

public virtual ICollection<Project> Projects { get; set; }

public virtual ICollection Projects {get;组; }

public virtual ICollection<MyCustomUser> Users { get; set; }

public virtual ICollection Users {get;组; }

and add on both entities:

并添加两个实体:

public virtual ICollection<Users2Projects> Users2Projects { get; set; }

public virtual ICollection Users2Projects {get;组; }

To add a new Project for an existing User you can:

要为现有用户添加新项目,您可以:

var relation = new Users2Projects() {
    User = existingUser, // reference retrieved from Context.
    Project = new Project() { Title = "Project Alpha" }
}

Context.Users2Projects.Add(relation);
Context.SaveChanges();

As far as I know, it is not possible to force the Project to have at least one User using a explicit relationship class on Entity Framework, so you would have to check that programmatically upon inserting a Project into the Context:

据我所知,不可能强制项目至少有一个用户在Entity Framework上使用显式关系类,因此在将项目插入Context时必须以编程方式检查:

if (project.Users2Projects.Count() == 0)
    throw new Exception("Project must have at least one user.")

Context.Projects.Add(project);
Context.SaveChanges();

and upon deleting an User you do the check before:

删除用户后,您可以进行以下检查:

var projectsToDelete = new List<Project>();

foreach (var relationship in user.Users2Projects)
{
    if (relationship.Project.Users2Projects.Count() <= 1)
        projectsToDelete.Add(relationship.Project);
}

Context.MyCustomUsers.Remove(user);
Context.Projects.RemoveRange(projectsToDelete);
Context.SaveChanges();

#2


You are clearly missing a conceptual entity here although you actually already modeled it a bit as your Users2Projects mapping table. You may want to untangle a few concepts around the bounded contexts that exist in your application, and look again at your requirements

虽然你实际上已经将它作为Users2Projects映射表进行了一些建模,但你显然在这里缺少一个概念实体。您可能想要围绕应用程序中存在的有界上下文解开几个概念,并再次查看您的要求

  1. User administration (i.e. administration of users that are allowed to access your system) seems to be a different concern than project administration:

    用户管理(即允许访问系统的用户的管理)似乎与项目管理不同:

    Because the user can use the application no matter if he has a Project or not.

    因为用户可以使用该应用程序,无论他是否有项目。

  2. In project administration, for the assignment of a user to a project, it appears there is additional information specific to the project that needs to be captured as part of the ProjectMemberAssignment. Your Project appears to be the aggregate root for this bounded context, and should be made responsible for managing it's member assignments:

    在项目管理中,为了将用户分配给项目,似乎有一些特定于项目的附加信息需要作为ProjectMemberAssignment的一部分被捕获。您的项目似乎是此有界上下文的聚合根,应该负责管理它的成员分配:

    public class Project
    {
        public virtual int Id { get; private set; }
        public string Title { get; set; }
    
        public void AssignMember(int userId, string someField, string someOtherField)
        {
            if (MemberAssignments.Any(x => x.UserId == userId))
                throw new InvalidOperationException("User already assigned");
            MemberAssignments.Add(new ProjectMemberAssignment(Id, userId, someField, someOtherField));
        }
    
        // Other behavior methods.
    
        public virtual ICollection<ProjectMemberAssignment> MemberAssignments 
        { 
            get;
            set; 
        } 
    }
    

Note that you can get the projects for a user using a simple query, without the need to maintain a many-to-many relationship in your model:

请注意,您可以使用简单查询为用户获取项目,而无需在模型中维护多对多关系:

var user = ...;
var projectsForUser =
    from project in db.Projects
    where project.MemberAssignments.Any(x => x.userId == user.UserId)
    select project;