Невозможно сохранить изменения, поскольку в данных, которые нужно сохранить, обнаружена циклическая зависимость - PullRequest
0 голосов
/ 08 марта 2020

Я пытаюсь добавить сущность ApplicationUser и Person в мой контекст

Мой 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();
}

Я пытаюсь создать обе эти сущности, а затем объединить их ie в методе RegisterUser моего UserService

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] <- Person {' PersonID '} ApplicationUser [Добавлено] <- Пользователь {' UserID '} Person [Добавлено]' </p>

Насколько я знаю, я думаю У меня установлены отношения правильно между ApplicationUser и Person, поэтому я не уверен, почему он не позволяет мне прикрепить Person к 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; }
}

1 Ответ

1 голос
/ 08 марта 2020

Мне удалось это исправить, удалив свойство PersonID в моем классе AspNetUser и основав мою новую настройку из Это руководство

Вот мой скорректированный класс 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 не изменился, поэтому я настроил метод RegisterUser в моем UserService, чтобы он выглядел так:

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;
    }
}

Это выглядит как будто это решено.

...