Pergunta

Eu tenho um mapeamento seguinte:

<set name="People" lazy="true" table="ProjectPeople">
  <key column="ProjectId" />
  <composite-element class="PersonRole">
    <many-to-one name="Person" column="PersonId" cascade="save-update" not-null="true" />
    <many-to-one name="Role" column="RoleId" cascade="save-update" not-null="true"  />
  </composite-element>
</set>

Agora, eu realmente não quero ter uma classe separada para função no domínio, preciso apenas do nome do papel. No entanto, nas funções de banco de dados ainda devem ser normalizadas para uma tabela separada Role (Id, Name).

Como faço para mapeá -lo para que as pessoas usem a aula de PersonRole?

public class PersonRole {
    public virtual Person Person { get; set; }
    public virtual string Role { get; set; }
}

Atualizar: Adicionado recompensa, parece uma pergunta útil não apenas para mim.

Foi útil?

Solução

Pessoalmente, eu criaria uma classe de função como Yassir

Mas se você deseja usar a estrutura que tem no momento, crie uma visualização que contém a tecla Foriegn para a tabela de sua pessoa e a descrição da função.

Modifique a tabela de mapeamento de configurações para apontar para sua nova visualização e modifique seu mapeamento de função para que seja uma propriedade em vez de muitas para um mapeamento.

No entanto, acho que a abordagem significará que você não poderá atualizar sua função, pois está reerencing uma visão.

Editar: Para atualizar a função que você pode adicionar <sql-insert>,<sql-update> and <sql-delete> para o seu arquivo de mapeamento para que a cascata-tudo funcionasse

Outras dicas

Você não receberá a resposta que espera, simplesmente porque não é possível. (N) O hibernato é uma estrutura de mapeamento de objetos-relatórios e suporte três tipos de mapeamento estratégias:

  • Tabela por hierarquia de classe
  • Tabela por subclasse
  • mesa por classe concreta

Ele também permite que você se desvie disso usando formula ou sql-insert etc, mas, como você descobriu, isso apenas causa mais dor no final, não são incentivados pela comunidade de hibernados e são ruins para a manutenção do seu código.

Solução?

Na verdade, é muito simples. Você não quer usar uma classe para Role. Eu suponho que você quer dizer que não quer expor uma classe de papel do tipo e que você não deseja digitar prObject.Role.Name o tempo todo. Apenas prObject.Role, que deve devolver uma string. Você tem várias opções:

  1. Use uma classe interna em, digamos, PersonRole, essa classe pode ser interna ou privada. Adicione uma função de propriedade que defina e atualiza um campo de membro;
  2. Use uma classe interna. Adicione uma função de propriedade que defina e atualiza um campo de membro;

Vamos examinar a opção 2:

// mapped to table Role, will not be visible to users of your DAL
// class can't be private, it's on namespace level, it can when it's an inner class
internal class Role 
{
    // typical mapping, need not be internal/protected when class is internal
    // cannot be private, because then virtual is not possible
    internal virtual int Id { get; private set; }
    internal virtual string Name { get; set; }
}

// the composite element
public class PersonRole
{
    // mapped properties public
    public virtual Person Person { get; set; }

    // mapped properties hidden
    internal virtual Role dbRole { get; set; }

    // not mapped, but convenience property in your DAL
    // for clarity, it is actually better to rename to something like RoleName
    public string Role     /* need not be virtual, but can be */
    { 
        get
        {
            return this.dbRole.Name;
        }
        set
        {
            this.dbRole.Name = value;    /* this works and triggers the cascade */
        }
    }
}

E o mapeamento pode parecer o esperado. Resultado: você não violou a regra de uma mesa por classe (EDIT: Asker diz que ele quer explicitamente violar essa regra, e o hib apoia -a, o que está correto), mas você escondeu os objetos da modificação e acesso usando técnicas típicas orientadas a objetos. Todos os recursos do NH (Cascade etc) ainda funcionam como esperado.

(N) O hibernato tem tudo a ver com esse tipo de decisões: como fazer uma camada de abstração bem pensada e segura ao seu banco de dados sem sacrificar a clareza, a brevidade ou a manutenção ou violar as regras OO ou ORM.


Atualização (depois que Q. foi fechado)

Outras excelentes abordagens que eu uso muito ao lidar com esse tipo de problema são:

  • Crie seus mapeamentos normalmente (ou seja, uma classe por mesa, eu sei que você não gosta, mas é o melhor) e use métodos de extensão:

     // trivial general example
     public static string GetFullName(this Person p)
     {
         return String.Format("{0} {1}", p.FirstName, p.LastName);
     }
    
     // gettor / settor for role.name
     public static string GetRoleName(this PersonRole pr)
     {
         return pr.Role == null ? "" : pr.Role.Name;
     }
     public static SetRoleName(this PersonRole pr, string name)
     {
         pr.Role = (pr.Role ?? new Role());
         pr.Role.Name = name;
     }
    
  • Crie seus mapeamentos normalmente, mas use partial classEs, que permite que você "decore" sua classe de que maneira desejar. A vantagem: se você usa o mapeamento gerado de suas mesas, você regenera sempre que desejar. Obviamente, as classes parciais devem ir em arquivos separados, por isso, considerando seu desejo de diminuir o "inchaço", isso provavelmente não é um bom cenário atualmente.

     public partial class PersonRole
     {
         public string Role {...}
     }
    
  • Talvez mais simples: apenas sobrecarregar ToString() por Role, o que o torna adequado para uso em String.Format E amigos, mas é claro que não o torna atribuível. Por padrão, cada classe de entidade ou poco deve ter um ToString() sobrecarga de qualquer maneira.

Embora seja possível fazer isso com o Nibernate diretamente, o q. foi fechado antes que eu tivesse tempo de olhar para ele (ninguém culpa, eu simplesmente não tinha tempo). Atualizarei se encontrar tempo para fazê -lo através do mapeamento HBM Hibernate, mesmo que eu não concorde com a abordagem. Não é bom lutar com conceitos avançados de HIB quando o resultado final é menos claro para outros programadores e menos claro (para onde foi essa tabela? Por que não há uma abstração de Idao para essa tabela? Veja também Nibernate práticas recomendadas e S#ARP). No entanto, o exercício é interessante, no entanto.

Considerando os comentários sobre "melhores práticas": em situações típicas, não deve ser apenas "uma classe por tabela", mas também um idaoxxx, um daoconcretexxx e um getdaoxxx para cada tabela, onde você usa a hierarquia de classe/interface para diferenciar entre entre Tabelas somente leitura e leitura/gravação. Isso é um mínimo de quatro classes/linhas de código por tabela. Isso geralmente é gerado automaticamente, mas fornece uma camada de acesso muito clara (DAO) à sua camada de dados (DAL). A camada de dados é melhor mantida o mais espartano possível. Nada dessas "práticas recomendadas" o impede de usar métodos de extensão ou métodos parciais para mover Role.Name em Role.

Estes são os melhores em geral práticas. Nem sempre é possível ou viável ou mesmo necessário em certos locais especiais ou típicos.

Eu não acho que é possível mapear muitos para um tipo primitivo se eu fosse você, adicionaria uma classe de função ao modelo

Este é o maior desligamento de toda a coisa purista do OO. Certamente o objetivo é ter um aplicativo de trabalho. Não é uma versão de alguns corpos de uma hierarquia de classe perfeita. E se você precisar codificar "Project.Role.name" em vez de "probject.role". Como isso ajuda você a tornar um programa melhor mais confiável?

Do ponto de vista purista do design do aplicativo, o que você deseja é simplesmente errado. Uma pessoa pode ter várias funções, um papel geralmente pode ser atribuído a várias pessoas. Por que ir a todo esse problema para fazer cumprir uma função irrealista por pessoa de classe Hierachy quando o modelo de dados não realizado é muitos papéis por pessoa?

Se você realmente tem uma regra "apenas uma função por pessoa", ela deve ser refletida no modelo de dados subjacente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top