Aviso:
1. Todas las "entidades" mencionadas en este artículo son generadas por LINQ TO SQL (es decir, .dbml)
2. Debe comprender cómo LINQ TO SQL implementa asociaciones de tablas, EntitySet y EntityRef.
Quizás después de ver el título pienses que la pregunta es relativamente abstracta, así que déjame darte un ejemplo para explicar el problema en detalle.
En la arquitectura de N niveles basada en LINQ TO SQL, si necesitamos actualizar una entidad, el proceso debería ser el siguiente:
proceso
BLL.GetModel(p=>p.id==1) --> Modificar el valor del atributo (campo) correspondiente --> BLL.Update(Entidad entidad) --> DAL.Update(Entidad entidad) --> Actualización exitosa
En este momento, necesitamos pasar esta entidad de la capa empresarial (BLL) a la capa de acceso a datos (DAL). Cuando el método GetModel devuelve la entidad, el DataContext se liberará inmediatamente y luego se volverá a instanciar cuando el DAL. Se ejecuta el método de actualización (entidad de entidad). Cree un DataContext para realizar la operación de actualización; se puede ver que la entidad pasada se pasa del primer DataContext a otro DataContext. Cuando se opera en diferentes DataContexts en LINQ TO SQL, es necesario realizar operaciones adicionales. se realizará primero, es decir, contexto.Entidad Adjuntar(entidad,verdadero); Finalmente contexto.SubmitChanges();
Echemos un vistazo al código:
código
clase BLL
{
DAL privado de solo lectura dal = nuevo DAL();
público LinqToSqlProvider.User GetModel (Expresión<Func<LinqToSqlProvider.User, bool>> expresión)
{
dal.GetModel(expresión);
}
Actualización pública vacía (entidad LinqToSqlProvider.User)
{
dal.Actualización(entidad);
}
}
clase DAL
{
público LinqToSqlProvider.User GetModel (Expresión<Func<LinqToSqlProvider.User, bool>> expresión)
{
Entrada LinqToSqlProvider.User = nueva CriTextBroadcast.LinqToSqlProvider.User();
usando (contexto CriTextBroadcastDBDataContext = DataContext)
{
entrada = contexto.User.SingleOrDefault(expresión);
}
entrada de regreso;
}
Actualización pública vacía (entidad LinqToSqlProvider.User)
{
usando (contexto CriTextBroadcastDBDataContext = DataContext)
{
contexto.Usuario.Attach(entrada, verdadero);
contexto.SubmitChanges();
}
}
}
De hecho, cuando usamos el código anterior para operar, ocurrirá esta excepción:
Se intentó adjuntar o agregar entidad, esta entidad no es una entidad nueva, se puede cargar desde otro DataContext...
Después de verificar mucha información sin éxito, finalmente vi una pregunta similar en una publicación extranjera. Resulta que la tabla correspondiente a esta entidad tiene varias tablas relacionadas, como por ejemplo: Usuario -> Mensaje, Usuario -> Imágenes, etc.
Atributos como EntitySet<Message> Message se generarán automáticamente al generar clases de entidad. Dado que no leemos estos contenidos asociados juntos al obtener la entidad, se producirá una excepción ObjectDisposed en estos atributos al adjuntar (Adjuntar). utilizado para consultar esta entidad ha sido publicado.
Solución:
código
/// <resumen>
/// La entidad auxiliar LinqToSql está separada del DataContext original
/// </summary>
/// <typeparam nombre="TEntity"></typeparam>
/// <param nombre="entidad"></param>
vacío estático público Separar<TEntity>(entidad TEntity)
{
Escriba t = entidad.GetType();
System.Reflection.PropertyInfo[] propiedades = t.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (propiedad var en propiedades)
{
nombre de cadena = propiedad.Nombre;
si (propiedad.PropertyType.IsGenericType &&
propiedad.PropertyType.GetGenericTypeDefinition() == tipode(EntitySet<>))
{
propiedad.SetValue(entidad, nulo, nulo);
}
}
System.Reflection.FieldInfo[] campos = t.GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
foreach (campo var en campos)
{
nombre de cadena = campo.Nombre;
si (campo.FieldType.IsGenericType &&
field.FieldType.GetGenericTypeDefinition() == tipode(EntityRef<>))
{
campo.SetValue(entidad, nulo);
}
}
System.Reflection.EventInfo eventPropertyChanged = t.GetEvent("PropertyChanged");
System.Reflection.EventInfo eventPropertyChanging = t.GetEvent("PropertyChanging");
si (eventPropertyChanged! = nulo)
{
eventPropertyChanged.RemoveEventHandler (entidad, nulo);
}
si (eventPropertyChanging! = nulo)
{
eventPropertyChanging.RemoveEventHandler (entidad, nulo);
}
}
Después de obtener la entidad, debe utilizar el método Detach(entity) para separar la entidad del DataContext original y luego adjuntarla al nuevo DataContext.