Я пытаюсь внедрить современные практики (с использованием сервисов, IoC и т. Д.) В моем проекте ASP.NET Web Forms, внедряя мой DbContext в класс сервиса, но продолжаю получать сообщение об ошибке An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
Это меня смущает, потому что я относительно уверен, что у меня есть только одно отслеживание изменений DbContext.
В чем проблема? Я использовал статические классы, которым я отправил DbContext в качестве параметров функции, но кроме этого, я ничего не изменил на стороне страницы ...
public partial class Create : System.Web.UI.Page
{
private LicenseService licenseService;
private ApplicationDbContext context = new ApplicationDbContext();
protected void Page_Load(object sender, EventArgs e)
{
try
{
licenseService = new LicenseService(context);
}
catch (Exception ex)
{
// TODO Add error handling/logging.
ErrorMessage.Text = ex.Message;
}
}
protected void Page_LoadComplete(object sender, EventArgs e)
{
this.context.Dispose();
}
protected async void Save_Click(object sender, EventArgs e)
{
try
{
var userManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = await userManager.FindByIdAsync(User.Identity.GetUserId());
await SaveLicenseAsync(user);
// Show a message that the work was done.
ShowSnackbar("License was successfully added; redirecting...", "Default");
}
catch (Exception ex)
{
// TODO Add error handling/logging.
ErrorMessage.Text = ex.Message;
}
}
private async Task SaveLicenseAsync(ApplicationUser user)
{
// Get the specified expiry date.
DateTime.TryParse(ExpiryDatePicker.SelectedDate.ToString(), out DateTime expiryDate);
// Create the viewmodel that will be passed to the service.
var model = new LicenseViewModel
{
ExpiryDate = expiryDate,
Name = NameTextBox.Text
};
await licenseService.AddAsync(model, user);
}
}
Мой сервис обычно взаимодействует с EF. Мне это нравится, потому что он отделяет страницу от логики DbContext. Я не люблю смешивать это. Вот как выглядит сервис:
публичный класс LicenseService
{
закрытый контекст ApplicationDbContext;
public LicenseService (ApplicationDbContext db)
{
context = db;
}
public List<LicenseViewModel> Get()
{
var factory = new LicenseViewModelFactory();
var licenses = context.Licenses.ToList();
return factory.GetViewModelList(licenses);
}
public List<LicenseViewModel> Get(string userId)
{
var factory = new LicenseViewModelFactory();
var licenses = context.Licenses.Where(x => x.User.Id == userId).ToList();
return factory.GetViewModelList(licenses);
}
public LicenseViewModel Get(int licenseId)
{
var factory = new LicenseViewModelFactory();
var license = context.Licenses.SingleOrDefault(x => x.Id == licenseId);
return factory.GetViewModel(license);
}
public async Task AddAsync(LicenseViewModel model, ApplicationUser owner)
{
var license = new License
{
ExpiryDate = model.ExpiryDate,
Name = model.Name,
User = owner
};
context.Licenses.Add(license);
await context.SaveChangesAsync();
}
public async Task AddRangeAsync(IEnumerable<LicenseViewModel> models, ApplicationUser owner)
{
var list = new List<License>();
foreach (var model in models)
{
list.Add(new License
{
ExpiryDate = model.ExpiryDate,
Name = model.Name,
User = owner
});
}
context.Licenses.AddRange(list);
await context.SaveChangesAsync();
}
public async Task UpdateAsync(LicenseViewModel model)
{
var license = context.Licenses.Single(x => x.Id == model.Id);
license.ExpiryDate = model.ExpiryDate;
license.Name = model.Name;
await context.SaveChangesAsync();
}
public async Task DeleteAsync(LicenseViewModel model)
{
var license = context.Licenses.Single(x => x.Id == model.Id);
context.Licenses.Remove(license);
await context.SaveChangesAsync();
}
public async Task DeleteAsync(int licenseId)
{
await DeleteAsync(Get(licenseId));
}
}