繁体   English   中英

保存实体对象时出现实体框架问题

[英]Entity Framework issue when saving an entity object

方案:Intranet应用程序。 Windows身份验证。 EF 6.1.3。 数据库:SQL Server Compact Edition和MS Access。 VS Studio 2013。

该解决方案包含3个项目:

EnqueteWeb.UI-ASP.NET Web应用程序; EnqueteWeb.Dominio-应用程序域的类库; ControleDeAcessoGeral-类库,用于获取从Active Directory登录的用户的数据,并包括/更新/删除/列出一些对应用程序执行某些特殊操作的用户。 由于对该应用程序的访问控制基于SQL Server Compact Edition数据库,因此我在ControleDeAcessoGeral中安装了EntityFramework。 我想在该项目的某个类中拥有与用户有关的所有方法。 所以我做到了。

这个ControleDeAcessoGeral项目的定义如下:

Aplicacao
-Corp.cs(处理Active Directory内容的方法)
-UsuariosApp.cs(处理SQL Server CE数据库的方法)
语境
-DBControleDeAcesso.cs(定义上下文)
-InicializaControleDeAcesso.cs(将初始数据填充到DBControleDeAcesso数据库中)

-Perfil.cs(用户可以在应用程序上拥有的配置文件)
-Usuarios.cs(可能会对应用执行某些操作的用户)
-UsuarioAD.cs(Active Directory用户及其数据)

DBControleDeAcesso.cs类具有以下代码:

using ControleDeAcessoGeral.Models.Entidades;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ControleDeAcessoGeral.Models.Contexto
{
    public class DBControleDeAcesso : DbContext
    {
        public DBControleDeAcesso() : base("ControleDeAcessoContext") { }

        public DbSet<Perfil> Perfis { get; set; }
        public DbSet<Usuario> Usuarios { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        }
    }
}  

实体类如下:
使用System.Collections.Generic; 使用System.ComponentModel.DataAnnotations;

namespace ControleDeAcessoGeral.Models.Entidades
{
    public class Usuario
    {
        [Key]
        public string Logon { get; set; }
        public string Nome { get; set; }
        [Display(Name="Órgão")]
        public string Orgao { get; set; }
        public string Email { get; set; }

        [StringLength(maximumLength: 4)]
        public string Depto { get; set; }

        [Display(Name = "Perfis")]
        public virtual List<Perfil> Perfis { get; set; }

        public Usuario()
        {
            this.Perfis = new List<Perfil>();
        }
    }
}  

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace ControleDeAcessoGeral.Models.Entidades
{
    public class Perfil
    {
        [Key]
        public int Id { get; set; }

        [Required(ErrorMessage = "Por favor, informe o NOME DO perfil.")]
        [StringLength(maximumLength: 25)]
        public string Nome { get; set; }

        [StringLength(maximumLength: 255)]
        [Display(Name = "Descrição")]
        public string Descricao { get; set; }

        public virtual List<Usuario> Usuarios { get; set; }

        public Perfil()
        {
            this.Usuarios = new List<Usuario>();
        }
    }
}  

而且,UsuariosApp.cs类如下所示(为简洁起见,我仅显示与该问题有关的方法):

using ControleDeAcessoGeral.Models.Contexto;
using ControleDeAcessoGeral.Models.Entidades;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;

namespace ControleDeAcessoGeral.Models.Aplicacao
{
    public class UsuariosApp
    {
        private DBControleDeAcesso db { get; set; }

        public UsuariosApp()
        {
            db = new DBControleDeAcesso();
        }

        public void SalvarUsuario(Usuario usuario)
        {
            db.Usuarios.Add(usuario);
            db.SaveChanges();
        }

        public Perfil LocalizarPerfil(int id)
        {
            return db.Perfis.Find(id);
        }
    }
}  

尝试在SQL Server CE数据库中保存用户(Usuarios.cs)的操作在AdministracaoController中,并且具有以下代码:

using ControleDeAcessoGeral.Models.Aplicacao;
using ControleDeAcessoGeral.Models.Entidades;
using EnqueteWeb.UI.Models;
using EnqueteWeb.UI.ViewModels;
using System.Linq;
using System.Web.Mvc;

namespace EnqueteWeb.UI.Controllers
{
    public class AdministracaoController : Controller
    {

        [HttpPost]
        public ActionResult CriarUsuarioNaApp(UsuarioViewModel model)
        {
            foreach (var item in model.PerfisSelecionados)
            {
                Perfil perfil = new UsuariosApp().LocalizarPerfil(item);
                model.Usuario.Perfis.Add(perfil);
            }
            if (ModelState.IsValid)
            {
                new UsuariosApp().SalvarUsuario(model.Usuario);
                return RedirectToAction("Usuarios");
            }
            return View(model);
        }
    }
}  

因此,当调用此动作CriarUsuarioNaApp并运行方法SalvarUsuario(model.Usuario)时 ,会发生以下错误:

一个IEntityChangeTracker的多个实例不能引用一个实体对象

我已经在网上阅读了一些有关此的内容,但不幸的是,我仍然无法使其正常工作。

希望有一个睿智善良的灵魂向我展示道路。

感谢您的关注。

保罗·里卡多·费雷拉

该问题是由于您在将所述实体附加到第二个DbContext实例之前不处置第一个DbContext实例(从中加载概要文件实体)而DbContext

要解决(以及一些其他建议):

  1. 已经UsuariosApp实现IDisposable和处置的您的实例DbContext db处置时UsuariosApp
  2. 将新使用的UsuariosApp实例包装在using语句中,并将此单个实例用于Perfil加载和Usuario保存逻辑
  3. 通过一次调用加载所有值来优化Perfil加载
  4. 立即验证ModelState.IsValid

像这样:

public class UsuariosApp : IDisposable
{
    private DBControleDeAcesso db { get; set; }

    public UsuariosApp()
    {
        db = new DBControleDeAcesso();
    }

    public void SalvarUsuario(Usuario usuario)
    {
        db.Usuarios.Add(usuario);
        db.SaveChanges();
    }

    public Perfil LocalizarPerfil(int id)
    {
        return db.Perfis.Find(id);
    }

    public IEnumerable<Perfil> LocalizarPerfiles( IEnumerable<int> ids )
    {
        return db.Perfils.Where( p => ids.Contains( p.Id ) )
            .ToArray();
    }

    private bool _disposed = false;

    protected virtual void Dispose( bool disposing )
    {
        if( _disposed )
        {
            return;
        }

        if( disposing )
        {
            db.Dispose();
        }

        _disposed = true;
    }

    public void Dispose()
    {
        Dispose( true );
        GC.SuppressFinalize( this );
    }
}

public ActionResult CriarUsuarioNaApp( UsuarioViewModel model )
{
    // validate model state first
    if( ModelState.IsValid )
    {
        // use single, disposable repo/uow instance
        using( var uapp = new UsuariosApp() )
        {
            // get all profiles in a single call, no loop required
            var perfils = uapp.LocalizarPerfiles( model.PerfisSelecionados );

            model.Usuario.Perfis.AddRange( perfils );

            uapp.SalvarUsuario( model.Usuario );
        }

        return RedirectToAction( "Usuarios" );
    }

    return View( model );
}

让我知道这是否不能解决您的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM