为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我的实体被多个 IEntityChangeTracker 实例引用?

为什么我的实体被多个 IEntityChangeTracker 实例引用?

C#
HUH函数 2022-10-23 13:41:42
我正在尝试通过将我的 DbContext 注入服务类来在我的 ASP.NET Web 窗体项目中实现现代实践(使用服务、IoC 等),但我一直收到一条错误消息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 逻辑分开。
查看完整描述

1 回答

?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

问题将与您在许可证中的用户参考有关。这是从 Owin 上下文中检索到的,但您正在尝试将其保存/关联到您的许可证上下文。


我将更新该方法以简单地接受用户 ID,然后从您的许可证上下文加载并关联用户。


public async Task AddRangeAsync(IEnumerable<LicenseViewModel> models, int ownerId)

{

    var list = new List<License>();

    var owner = context.Users.Single(x => x.UserId == ownerId);

    foreach (var model in models)

    {

        list.Add(new License

        {

            ExpiryDate = model.ExpiryDate,

            Name = model.Name,

            User = owner

        });

    }

    context.Licenses.AddRange(list);

    await context.SaveChangesAsync();

}

那应该可以解决您的问题。偷偷摸摸的小细节。:)


为了避免负载,您可以使用:


var owner = context.Owners.Local.SingleOrDefault(x => x.UserId == ownerId);

if (owner == null)

{

    owner = new User{UserId = ownerId};

    context.Users.Attach(owner);

}

// ...

我可能会考虑将其放在基类方法中以从上下文中检索所有者引用。该方法的警告是,除非您从数据库显式加载,否则此上下文中的用户将不包含有关用户的详细信息。(即名称等)因此,只要团队知道不相信上下文将具有完整的用户,除非明确重新加载,就可以从性能 PoV 中获得。


查看完整回答
反对 回复 2022-10-23
  • 1 回答
  • 0 关注
  • 89 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信