Entity Framework 如何引用一行而不是创建新行
Entity Framework How to reference a row instead of create new row
我有 2 tables Gender 和 ApplicationUser。
我希望 ApplicationUser 中的每个用户在 Gender table 中引用一个性别。
但现在在创建每个 applicationUser 实例后,在 Gender table 中创建了一个新的性别。请注意,我最近将性别名称设置为唯一,但它引发了异常。
这是我的代码
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();
}
在这种情况下,您只需将 Gender
属性 分配给现有 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();
感谢 @GertArnold 的评论。
将近 2 周后,我找到了解决方案,该解决方案位于程序流程的中间位置,我正在创建 DatabaseContext[=33 的新实例=] 这就是问题所在。
通过实践我发现在这种方法中你必须有一个 DatabaseContext 的实例,其次在我的情况下我正在创建一个新的 ApplicationUser 并且我想将 Gender 引用分配给新创建的用户,这是错误的,因为我没有引用 UserManager DatabaseContext 所以系统试图创建新的性别实例 Unique 属性 并且 exception.So 我创建了 ApplicationUser 然后在我想分配的相同上下文中获取它 Gender.
我有 2 tables Gender 和 ApplicationUser。 我希望 ApplicationUser 中的每个用户在 Gender table 中引用一个性别。 但现在在创建每个 applicationUser 实例后,在 Gender table 中创建了一个新的性别。请注意,我最近将性别名称设置为唯一,但它引发了异常。
这是我的代码
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();
}
在这种情况下,您只需将 Gender
属性 分配给现有 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();
感谢 @GertArnold 的评论。
将近 2 周后,我找到了解决方案,该解决方案位于程序流程的中间位置,我正在创建 DatabaseContext[=33 的新实例=] 这就是问题所在。 通过实践我发现在这种方法中你必须有一个 DatabaseContext 的实例,其次在我的情况下我正在创建一个新的 ApplicationUser 并且我想将 Gender 引用分配给新创建的用户,这是错误的,因为我没有引用 UserManager DatabaseContext 所以系统试图创建新的性别实例 Unique 属性 并且 exception.So 我创建了 ApplicationUser 然后在我想分配的相同上下文中获取它 Gender.