2009-03-13 13 views
22

cuando cargo una clase de tareas, la propiedad de documentos es siempre nula, a pesar de ser datos de la db.nhibernate fluidez hasOne WithForeignKey no trabajar

clase

Tarea:

public class Task 
{ 
    public virtual Document Document { get; set; } 

Grupo de Cartografía anulación para AutoPersistenceModel:

public void Override(AutoMap<Task> mapping) 
{ 
    mapping.HasOne(x => x.Document) 
     .WithForeignKey("Task_Id"); 

Como se puede ver forman lo NHProf dice es que se está ejecutando, la condición de unión está mal, el imposible de WithForeignKey parecen tomar efecto. De hecho, puedo escribir cualquier cadena en el código anterior y no hace ninguna diferencia.

FROM [Task] this_ 
    left outer join [Document] document2_ 
    on this_.Id = document2_.Id 

Debería ser:

FROM [Task] this_ 
    left outer join [Document] document2_ 
    on this_.Id = document2_.Task_Id 

Si yo hackearé los datos en la base de datos de manera que los identificadores coinciden, entonces se cargan los datos, pero es evidente que esto no es correcto - pero al menos demuestra que las cargas datos.

Editar: hurgar en la fuente NHib fluidez para encontrar el código XML produce esto:

<one-to-one foreign-key="Task_Id" cascade="all" name="Document" class="MyProject.Document, MyProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 

Editar: aquí está el esquema:

CREATE TABLE [dbo].[Document](
[Id] [int] IDENTITY(1,1) NOT NULL, 
[Task_Id] [int] NOT NULL, 

CREATE TABLE [dbo].[Task](
[Id] [int] IDENTITY(1,1) NOT NULL, 

Alguien tiene alguna idea?

Gracias

Andrew

Respuesta

5

Creo que el problema aquí es que la convención "hasOne" significa que usted está señalando a la otra cosa (la forma relacional estándar para decir "muchos a uno"/"Una a uno"); Al poner un Task_ID en el documento, la relación real es un HasMany, pero usted tiene algún tipo de entendimiento implícito de que solo habrá un documento por tarea.

Lo siento, no sé cómo solucionarlo, pero estaré interesado en ver cuál es la solución (no uso NHibernate ni NHibernate fluido, pero lo he estado investigando para usarlo en el futuro) . Una solución (de alguien con muy poca idea) sería convertir Documents en una colección en Task, y luego proporcionar una propiedad Document que devuelva la primera en la colección (utilizando una interfaz que oculte la propiedad Documents para que nadie crea que puedan agregar nuevos artículos)

Mirando a través de la documentación y teniendo en cuenta la respuesta de eulerfx, tal vez el enfoque sería algo así como:

References(x => x.Document) 
    .TheColumnNameIs("ID") 
    .PropertyRef(d => d.Task_ID); 

EDIT: Sólo para que esta respuesta tiene la solución apropiada: La ruta correcta es para actualizar el esquema de base de datos para que coincida con el intención del código. Eso significa agregar un DocumentID a la tabla de tareas, por lo que hay una relación de muchos a uno entre Tarea y Documento. Si los cambios de esquema no fueran posibles, References() sería la resolución adecuada.

+0

Un posibilidad estoy de acuerdo, pero ¿por qué Task_Id no se procesa en ningún lado? (Aunque su mal y que, por tanto, provocar una excepción - pero, duerma) –

+0

que hace el trabajo, sin embargo, significa que necesito una propiedad task_id el documento, que preferiría no tener. Funciona por ahora aunque gracias –

6

que puedes usar:

Referencias (x => x.Documento, "DocumentIdColumnOnTask")

+0

tblDocument tiene task_id, no ha tblTask ​​id_documento –

+0

Oh bien perdido esa parte. Entonces supongo que tendría más sentido tener un docID en la mesa de trabajo. De lo contrario, la estructura de la tabla indica que tal vez haya varios documentos para una tarea. – eulerfx

+0

Sí, supongo que sí. Había una razón por la que es así pero no puedo recordar por qué. Voy a pensar y considerar revertirlo. ta –

0

Como eulerfx señaló,

la estructura de la tabla indica que tal vez haya numerosas documentos para una tarea

y Chris declaró:

Por al poner un Task_ID en el documento, la relación real es un HasMany, pero usted tiene algún tipo de entendimiento implícito de que solo habrá un documento por tarea.

Esto es por supuesto correcto, así que lo he invertido, por lo que Task tiene un Document_Id nulo.

Gracias a los dos por su ayuda!

¡Lancé una moneda por la respuesta aceptada, si pudiera marcar ambas cosas lo haría!

+0

hola andrew, PLN está en defo la respuesta. Diría que al volver a hacer el DB has hecho lo correcto. Pero a veces no puedes cambiar la base de datos, y aquí es donde realmente fluyen las asignaciones fluidas. HasOne es una de esas funciones, y tanto usted como yo estábamos utilizándola incorrectamente. PLN señala la forma correcta de usarlo ... mis 2 centavos – andy

91

me encontré con el mismo problema hoy en día. Creo que el truco no es usar .ForeignKey (...) con la asignación .HasOne, sino usar .PropertyRef (...) en su lugar. El siguiente es cómo definir un uno-a-uno entre una Organización (Padre) y su administración (niño):

HasOne(x => x.Admin).PropertyRef(r => r.Organisation).Cascade.All(); 

La administración tiene una simple referencia a la Organización utilizando su clave externa:

References(x => x.Organisation, "ORAD_FK_ORGANISATION").Not.Nullable(); 

Al recuperar una organización, esto cargará la correcta registro de administrador y correctamente las actualizaciones y eliminaciones en cascada.

+0

Parece que la respuesta perfecta sería una combinación de esto y la respuesta de Chris Shaffer. Esta respuesta proporciona una implementación de trabajo usando Fluent NHibernate y Chris Shaffer proporciona un poco de 'teoría' sobre por qué la implementación inicial no funcionaba. –

+0

Gracias ... funcionó para mí – dbones

+0

funcionó para mí también, muchas gracias. Pero, ¿para qué es HasOne(). ForeignKey()? – whitestream

0

He estado luchando con el mismo problema tiene uno y finalmente encontraron que esto funcionó:

public class ParentMap : ClassMap<Parent> 
{ 
    public ParentMap() 
    { 
     Id(x => x.Id); 
     HasOne(s => s.Child).Cascade.All(); 
    } 
} 

public class ChildMap : ClassMap<Model.Child> 
{ 
    public ChildMap() 
    { 
     Id(x => x.Id); 
     HasOne(s => s.Parent).Constrained().ForeignKey();   
    } 
} 
+0

cómo hacer con compositeid en ambas tablas? – DanielVorph

2

que he probado esta solución:

justo en el Documento:

mapping.HasOne(x => x.Task).ForeignKey("Task_ID").Constrained().Cascade.All(); 
Cuestiones relacionadas