实体框架如何引用行而不是创建新行

时间:2017-09-27 08:21:54

标签: asp.net-mvc entity-framework unique-constraint unique-key

我有2个表 性别 ApplicationUser 。 我希望ApplicationUser中的每个用户在Gender表中引用性别。 但现在在创建每个applicationUser实例后,在Gender表中创建了一个新的性别。请注意,我最近将性别名称设为Unique,它会引发异常。

这是我的代码

public sealed class Uow : IUow, IDisposable {

    public Uow(IRepositoryProvider repositoryProvider) {
        CreateDbContext();
        repositoryProvider.DbContext = DbContext;
        RepositoryProvider = repositoryProvider;

    }

    public IApplicationUserRepository ApplicationUsers => GetRepo<IApplicationUserRepository>();
    public IFileExtensionRepository FileExtensions => GetRepo<IFileExtensionRepository>();
    public IFileRecordRepository FileRecords => GetRepo<IFileRecordRepository>();
    public IFileTypeRepository FileTypes => GetRepo<IFileTypeRepository>();
    public IGenderRepository Genders => GetRepo<IGenderRepository>();
    public IMembershipClassRepository MembershipClass => GetRepo<IMembershipClassRepository>();

    public async Task<int> CommitAsync() {
        return await DbContext.SaveChangesAsync();
    }

    public void DiscardChanges() {
        var changedEntries = DbContext.ChangeTracker.Entries()
            .Where(x => x.State != EntityState.Unchanged)
            .ToList();

        foreach (var entry in changedEntries) {
            switch (entry.State) {
                case EntityState.Modified:
                case EntityState.Deleted:
                    entry.State = EntityState.Modified; //Revert changes made to deleted entity.
                    entry.State = EntityState.Unchanged;
                    break;
                case EntityState.Added:
                    entry.State = EntityState.Detached;
                    break;
                case EntityState.Detached:
                    break;
                case EntityState.Unchanged:
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
    }

    private T GetRepo<T>() where T : class {
        return RepositoryProvider.GetRepository<T>();
    }

    private void CreateDbContext() {
        DbContext = new DatabaseContext();
        DbContext.Configuration.ProxyCreationEnabled = false;
        DbContext.Configuration.LazyLoadingEnabled = false;
        DbContext.Configuration.ValidateOnSaveEnabled = false;
    }

    private DatabaseContext DbContext {
        get; set;
    }

    private IRepositoryProvider RepositoryProvider {
        get; set;
    }
}

public class GenderRepository : EfRepository<Gender>, IGenderRepository {
    public GenderRepository(DatabaseContext dbContext) : base(dbContext) { }

    public async Task<Gender> GetByNameAsync(string genderName) {
        return await DbContext.Gender.SingleAsync(x => x.Name == genderName);
    }
}

public class Gender {
    public const string Male = "Male";
    public const string Female = "Female";
    public const string NotSpecified = "NotSpecified";

    [Key]
    public int Id { get; set; }

    [MaxLength(12), Index(IsUnique = true)]
    public string Name { get; set; }
}

public class ApplicationUser : IdentityUser {
    [MinLength(3), MaxLength(16)]
    public string DisplayName { get; set; }

    [MaxLength(128), MinLength(2), DefaultValue(null)]
    public string FirstName { get; set; }

    [MaxLength(128), MinLength(2), DefaultValue(null)]
    public string LastName { get; set; }

    public Gender Gender{ get; set; }
}

async Task Register(RegisterViewModel model) {
    // doing some stuff
    user = new ApplicationUser {
        Email = model.Email,
        DisplayName = model.DisplayName,
        Gender = await Uow.Genders.GetByNameAsync(Gender.NotSpecified),
        MembershipClass = await Uow.MembershipClass.GetByNameAsync(MembershipClass.Normal),
    };

    user.ProfilePicture = new FileRecord();

    user.ProfilePicture.Name = "Profile";
    user.ProfilePicture.FileType = await Uow.FileTypes.GetByNameAsync(FileType.ProfileImage);
    user.ProfilePicture.Extension = await Uow.FileExtensions.GetByNameAsync(FileExtension.JPG);
    user.ProfilePicture.Size = 18932;

    // doing some stuff
    await UserManager.CreateAsync(user, model.Password);
    await Uow.CommitAsync();
}

2 个答案:

答案 0 :(得分:1)

在这种情况下,您只需指定Gender属性以引用现有new,而不是通过var maleGender = context.Genders.Single(x => x.Name == Gender.Male); var newUser = new ApplicationUser { Gender = maleGender //wrong approach: //Gender = new Gender { Name = Gender.Male } }; context.SaveChanges(); 关键字创建一个:

$rs = $this->db->select('ult_camp.*,ult_country.name as country_name,ult_state.name as state_name')
                    ->join('ult_country', 'ult_country.id = ult_camp.country_id')
                    ->join('ult_state', 'ult_state.id = ult_camp.state_id ')
                    ->from('ult_camp')
                    ->where("'org_fname' NOT IN (SELECT 'name' FROM 'ult_coach')", NULL, FALSE)
                    ->where('ult_camp.status', 'Active')
                    ->where('ult_state.status', 'Active')
                    ->where('ult_country.status', 'Active')
                    ->get()->result(); 

答案 1 :(得分:0)

感谢 @GertArnold 的评论。

经过近两周的时间,我找到了一个解决方案,其中一些方法流程的中间方式我正在创建一个新的 DatabaseContext 实例,这就是问题所在。 通过实践,我发现在这种方法中你必须有单个 DatabaseContext 的实例,其次在我的情况下,我正在创建一个新的 ApplicationUser 和我想将 Gender 引用分配给新创建的用户,这是错误的,因为我没有引用 UserManager DatabaseContext 所以系统尝试创建新的性别实例,它是 唯一 属性和原因和异常。所以我创建了 ApplicationUser ,然后在我想要分配 性别 的相同上下文中获取它。