场景: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数据库的方法)
Contexto
- DBControleDeAcesso.cs(定义上下文)
- InicializaControleDeAcesso.cs(填写初始数据到
DBControleDeAcesso数据库)
Entidades
- 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的多个实例无法引用实体对象
我在网上看过一些关于此事的内容,但不幸的是,我仍然无法使其发挥作用。
希望一个聪明善良的灵魂会指引我。
感谢您的关注。
Paulo Ricardo Ferreira
答案 0 :(得分:0)
问题源于这样一个事实:在将所述实体附加到第二个DbContext
实例之前,您没有丢弃第一个DbContext
实例(从中加载配置文件实体)。
修复(及其他一些建议):
UsuariosApp
实施IDisposable
并在处置DbContext
db
UsuariosApp
实例
UsuariosApp
实例包装在using
语句中,并将此单个实例用于Perfil
加载和Usuario
保存逻辑Perfil
加载
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 );
}
如果这不能解决您的问题,请告诉我。