【问题标题】:Unable to save changes because a circular dependency was detected in the data to be saved无法保存更改,因为在要保存的数据中检测到循环依赖
【发布时间】:2020-06-20 15:13:28
【问题描述】:

我正在尝试将 ApplicationUserPerson 实体添加到我的上下文中

我的ApplicationUser 班级

public class ApplicationUser : IdentityUser<Guid>
{
    public int? PersonID { get; set; }

    [ForeignKey("PersonID")]
    public Person Person { get; set; }

    [InverseProperty("User")]
    public ICollection<UserSource> UserSources { get; set; }

    public virtual ICollection<IdentityUserClaim<Guid>> Claims { get; set; }
    public virtual ICollection<IdentityUserLogin<Guid>> Logins { get; set; }
    public virtual ICollection<IdentityUserToken<Guid>> Tokens { get; set; }
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

我的Person 班级

public class Person : BaseEntity
{
    [Required]
    [DataType(DataType.Text)]
    public string FirstName { get; set; }

    [Required]
    [DataType(DataType.Text)]
    public string LastName { get; set; }

    [Required]
    [DataType(DataType.Text)]
    public string FullName { get; set; }

    public int HeightInches { get; set; }

    public int WeightPounds { get; set; }

    [DataType(DataType.Text)]
    public string BatHand { get; set; }

    [DataType(DataType.Text)]
    public string ThrowHand { get; set; }

    public DimDate BirthDate { get; set; }

    public DimDate DeathDate { get; set; }

    public DimDate DebutDate { get; set; }
    public DimDate FinalDate { get; set; }
    public Guid? UserID { get; set; }

    [ForeignKey("UserID")]
    public ApplicationUser User { get; set; }

    [InverseProperty("LeagueOwner")]
    public ICollection<League> LeaguesOwned { get; set; }

    public override int GetHashCode() => Tuple.Create(this.FirstName, this.LastName, this.FullName).GetHashCode();
}

我正在尝试创建这两个实体,然后在我的UserServiceRegisterUser 方法中将它们绑定在一起

Public Class UserService : IUserService
{
    private MyDbContext context;
    private ILogger logger;
    private UserManager<ApplicationUser> userManager;

    public async Task<ApplicationUser> RegisterUser(RegistrationModel registrationModel)
    {
        // Create the User first
        var user = new ApplicationUser
        {
            UserName = registrationModel.UserName,
            Email = registrationModel.Email
        };

        // Create the User with a password
        var result = await this.userManager.CreateAsync(user, registrationModel.Password);

        // Make sure the user is successfully created
        if (result.Succeeded)
        {
            try
            {
                this.logger.LogInformation($"User {user.UserName} successfully created and added to the database");

                // create a person for the User (this is causing me to have a headache...)
                // I originally had this is separate methods... moving into one so I can make more sense
                var fullName = (registrationModel.FirstName == registrationModel.LastName) ? registrationModel.FirstName : registrationModel.FirstName + " " + registrationModel.LastName;
                var newPerson = new Person
                {
                    FirstName = registrationModel.FirstName,
                    LastName = registrationModel.LastName,
                    FullName = fullName
                };

                // Add the person to the DB
                await this.context.People.AddAsync(newPerson);

                // Add the User to the Person and vice versa
                user.Person = newPerson;
                newPerson.User = user;

                // Save the changes
                await this.context.SaveChangesAsync();
                this.logger.LogInformation($"Person for {user.NormalizedUserName} created");

                // Add source to the user
                var userSource = new UserSource
                {
                    MySource = registrationModel.WhereDidYouHear,
                    User = user
                };

                await this.context.UserSources.AddAsync(userSource);
                this.logger.LogInformation($"Source added to UserSources for {user.NormalizedUserName}");

                return user;
            }
            catch (Exception e)
            {
                this.logger.LogError(e);
                return null;
            }
        }
        foreach (var error in result.Errors)
        {
            this.logger.LogError(error.Description);
        }

        return null;
    }
}

但是,当此方法执行时,我的日志中出现以下错误:

System.InvalidOperationException:无法保存更改,因为在要保存的数据中检测到循环依赖:'Person [Added]

据我所知,我认为我在ApplicationUserPerson 之间建立了正确的关系,所以我不确定为什么它不允许我附加@ 987654333@ 到 ApplicationUser 反之亦然。

我将包含RegistrationModel 以供参考,因为其中的数据用于RegisterUser 方法:

public class RegistrationModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [RegularExpression(@"^[a-zA-Z0-9_]{5,255}$")]
    [Required]
    [StringLength(256)]
    [Display(Name = "UserName")]
    public string UserName { get; set; }

    [Required]
    [StringLength(256)]
    public string FirstName { get; set; }

    [Required]
    [StringLength(256)]
    public string LastName { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
    public string Password { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

    [DataType(DataType.Text)]
    [Display(Name = "Where did you hear about us?")]
    public string WhereDidYouHear { get; set; }
}

【问题讨论】:

  • 如果你的Person 在你的ApplicationUser 上有一个外键,而你的ApplicationUser 在你的Person 上有一个外键,当它们都依赖时,如何创建一个另一方面要创建一个ID作为外键写?何时尚未创建外键实体?
  • ...这是一个很好的问题。所以我应该只指向另一个而不是相反?

标签: c# asp.net-mvc entity-framework-core


【解决方案1】:

我可以通过删除AspNetUser 类中的PersonID 属性来解决此问题,并基于This Tutorial 的新设置

这是我调整后的AspNetUser 类:

public class ApplicationUser : IdentityUser<Guid>
{
    [InverseProperty("User")]
    public Person Person { get; set; }

    [InverseProperty("User")]
    public ICollection<UserSource> UserSources { get; set; }

    [InverseProperty("Owner")]
    public ICollection<League> LeaguesOwned { get; set; }

    public virtual ICollection<IdentityUserClaim<Guid>> Claims { get; set; }
    public virtual ICollection<IdentityUserLogin<Guid>> Logins { get; set; }
    public virtual ICollection<IdentityUserToken<Guid>> Tokens { get; set; }
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

我的Person 类没有改​​变,所以我调整了UserService 中的RegisterUser 方法,使其看起来像这样:

public class UserService : IUserService
{
    private StatPeekContext context;
    private ILogger logger;
    private UserManager<ApplicationUser> userManager;

    /// <summary>
    /// This will register a new user
    /// </summary>
    /// <param name="registrationModel"></param>
    /// <returns></returns>
    public async Task<ApplicationUser> RegisterUser(RegistrationModel registrationModel)
    {
        // Create the User first
        var user = new ApplicationUser
        {
            UserName = registrationModel.UserName,
            Email = registrationModel.Email
        };

        // Create the User with a password
        var result = await this.userManager.CreateAsync(user, registrationModel.Password);

        // Make sure the user is successfully created
        if (result.Succeeded)
        {
            try
            {
                this.logger.LogInformation($"User {user.UserName} successfully created and added to the database");

                var fullName = (registrationModel.FirstName == registrationModel.LastName) ? registrationModel.FirstName : registrationModel.FirstName + " " + registrationModel.LastName;
                var newPerson = new Person
                {
                    FirstName = registrationModel.FirstName,
                    LastName = registrationModel.LastName,
                    FullName = fullName,
                    UserID = user.Id
                };

                // Add the person to the DB
                await this.context.People.AddAsync(newPerson);

                this.logger.LogInformation($"Person for {user.NormalizedUserName} created");

                // Add source to the user
                var userSource = new UserSource
                {
                    MySource = registrationModel.WhereDidYouHear,
                    UserID = user.Id
                };

                await this.context.UserSources.AddAsync(userSource);
                await this.context.SaveChangesAsync();
                this.logger.LogInformation($"Source added to UserSources for {user.NormalizedUserName}");

                return user;
            }
            catch (Exception e)
            {
                this.logger.LogError(e);
                return null;
            }
        }
        foreach (var error in result.Errors)
        {
            this.logger.LogError(error.Description);
        }

        return null;
    }
}

这看起来解决了它。

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 1970-01-01
    • 2016-02-07
    • 2016-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 2015-02-20
    相关资源
    最近更新 更多