2010-05-18 24 views
0

Nous avons une vieille application asp.net avec nhibernate, que nous étendons et améliorons. NHibernate utilisé était assez ancien (1.0.2.0), nous avons donc décidé de passer à (2.1.2) pour les nouvelles fonctionnalités. Les fichiers HBM sont générés via un modèle personnalisé avec MyGeneration. Tout s'est bien passé, sauf pour une chose.Migration de Nhibernate de 1.0.2.0 à 2.1.2 et problèmes d'enregistrement plusieurs-à-un

Disons que nous avons des objets Blog et Post. Le blog peut contenir de nombreux messages, de sorte que Post aura des relations plusieurs-à-un. En raison du mode de fonctionnement de cette application, la relation n'est pas effectuée via les clés primaires, mais via la colonne Blog.Reference.

Exemples de fichiers de mapings et .cs:

<?xml version="1.0" encoding="utf-8" ?> 

<id name="Id" column="Id" type="Guid"> 
     <generator class="assigned"/> 
    </id> 
    <property column="Reference" type="Int32" name="Reference" not-null="true" /> 
    <property column="Name" type="String" name="Name" length="250" /> 
</class> 

<?xml version="1.0" encoding="utf-8" ?> 

<id name="Id" column="Id" type="Guid"> 
     <generator class="assigned"/> 
    </id> 

    <property column="Reference" type="Int32" name="Reference" not-null="true" /> 
    <property column="Name" type="String" name="Name" length="250" /> 
    <many-to-one name="Blog" column="BlogId" class="SampleNamespace.BlogEntity,SampleNamespace" property-ref="Reference" /> 
</class> 

et fichiers classe

class BlogEntity 
{ 
    public Guid Id { get; set; } 
    public int Reference { get; set; } 
    public string Name { get; set; } 
} 

class PostEntity 
{ 
    public Guid Id { get; set; } 
    public int Reference { get; set; } 
    public string Name { get; set; } 
    public BlogEntity Blog { get; set; } 
} 

Maintenant, supposons que que j'ai un blog avec Id 1D270C7B-090D-47E2-8CC5-A3D145838D9C et avec référence 1

Dans la vieille NHibernate telle chose était possible:

 //this Blog already exists in database 
     BlogEntity blog = new BlogEntity(); 
     blog.Id = Guid.Empty; 
     blog.Reference = 1; //Reference is unique, so we can distinguish Blog by this field 
     blog.Name = "My blog"; 

     //this is new Post, that we are trying to insert 
     PostEntity post = new PostEntity(); 
     post.Id = Guid.NewGuid(); 
     post.Name = "New post"; 
     post.Reference = 1234; 
     post.Blog = blog; 

     session.Save(post); 

Cependant, dans une nouvelle version, je reçois une exception qui ne peut pas insérer NULL dans Post.BlogId. Comme je comprends, dans l'ancienne version, pour nhibernate il suffisait d'avoir un champ Blog.Reference, et il pouvait récupérer l'entité par ce champ, et l'attacher à PostEntity, et lors de l'enregistrement de PostEntity, tout fonctionnerait correctement. Et si je comprends bien, NHibernate essaie seulement de récupérer par Blog.Id.

Comment résoudre ce problème? Je ne peux pas changer de design de DB, je ne peux pas non plus attribuer d'identifiant à BlogEntity, car les objets sont hors de mon contrôle (ils sont pré-remplis comme des "ojbects" génériques comme ça)

Répondre

0

Il me semble très étrange que le code travaillé dans le New Hampshire 1. Mais, puisqu'il est, je pense que vous avez ne fonctionne pas au moment de toute façon de chercher l'entité blog dans une première requête:

var criteria = DetachedCriteria.For<Blog>(); 
criteria.Add(Expression.Eq("Reference", 1)); 
var blog = criteria.GetExecutableCriteria(session).List<Blog>().FirstOrDefault(); 

post.Blog = blog; 
session.Save(post); 
+0

Malheureusement, je ne peux pas faire comme ça. Disons que j'ai plus de 50 objets différents, et ils entrent par la méthode "générique" démodée - disons InsertEntity (entité objet). Et l'entité pourrait être Blog, pourrait être Post, pourrait être utilisateur, pourrait être autre chose ... Et le pire - je ne peux pas changer cette méthode, parce que c'est hors de mon contrôle – Meska

+0

Je ne comprends toujours pas pourquoi vous ne pouvez pas fais le. Vous avez une session.Enregistrez (post) dans votre code d'origine, ce n'est pas différent dans mon code. Et le code que j'ai ajouté ne fait qu'une requête pour rechercher l'entité Blog par sa référence. Alors, quel est exactement le problème? Si le problème est que vous ne pouvez pas changer le code, je vous suggère de ne pas introduire une nouvelle bibliothèque NHibernate. –

+0

Ce scénario Blog/Post est juste une preuve de concept de ce qui se passe. C'est beaucoup plus compliqué, et la méthode save est la plus proche: InserEntity (entité objet) { // effectue un traitement. entité est vraiment générique session.save } et je ne peux pas modifier la signature d'InserEntity (entité objet). De toute façon, merci pour l'aide :), et il semble que nous allons sauter l'introduction de nhibernate nouveau, s'il n'y a pas de solution possible dans quelques jours – Meska

0

cette

blog.Id = Guid.Empty 

est traduit par une valeur nulle dans la base de données. Ainsi, lorsque vous le modifiez (comme l'indique l'exemple de code), vous définissez explicitement une valeur nulle sur l'identifiant BlogEntity.

C'est l'erreur que vous recevez et n'est pas pertinent de la colonne/propriété "Référence". En ce qui concerne la question de savoir ce que vous pouvez faire ... eh bien, vous n'avez pas à faire que l'ORM se joigne aux Guids! Vous pouvez faire les jointures sur la colonne Référence ...

+0

Mais comment se fait-il que cela a fonctionné dans 1.0.2.0? Pourriez-vous expliquer plus sur ORM faisant des jointures sur la référence? Des mots clés pour que je puisse google plus d'infos? Merci – Meska

+0

J'ai trouvé beaucoup de différences de 1.2 à 2 ++ avec la plupart étant que les versions 2 ++ sont plus strictes sur les règles. Maintenant, en ce qui concerne les jointures, juste parce que vous avez un DB PK, cela ne signifie pas que vous devez réellement le mapper en tant que tel. Vous pouvez mapper la colonne Reference en tant qu'ID de l'entité, mais être prêt à effectuer de nombreux tests et à vous assurer que le PK Guid actuel est toujours inséré, etc. Le problème provient d'un mauvais schéma db, ne vous attendez donc pas à ce que NHibernate par magie résoudre cela pour vous. – Jaguar

0

Répondre à ma propre question.

Le problème était que nhibernate utilisait DB pour récupérer BlogEntity avec l'ID 00000000-0000-0000-0000-000000000000. Bien sûr, dans DB, il n'a rien, il a essayé d'insérer null

Et il était clairement visible dans les journaux pourquoi il se passait

Impossible de déterminer si BlogEntity avec identifiant attribué 00000000-0000-0000 -0000-000000000000 est transitoire ou détaché; interroger la base de données. Utilisez explicitement Save() ou Update() en session pour éviter cela.

résolu ma mise en œuvre IInterceptor, en passant à la session et surtout sa méthode bool? IsTransient(object entity)

Et le problème est résolu.