isessionfactory fluently c# nhibernate fluent-nhibernate nhibernate-mapping

fluently - nhibernate c#



ProgramaciĆ³n de interfaces mientras mapeo con Fluent NHibernate (5)

Estoy teniendo exactamente el mismo problema. Desafortunadamente tengo una razón válida para usar interfaces de entidad; El modelo de entidad se implementará de diferentes maneras y con diferentes asignaciones por cliente.

El modelo completo debe ser de solo lectura, por lo que las interfaces son del estilo:

public interface IAccount { long AccountId { get; } IHouse House { get; } } public interface IHouse { long HouseId { get; } HouseStatus Status { get; } IList<IAccount> Accounts { get; } }

Implementaciones concretas luego implementan estos con setters internos:

public class Account: IAccount { public virtual long AccountId { get; internal set; } public virtual IHouse House { get; internal set; } } public class House: IHouse { public virtual long HouseId { get; internal set; } public virtual HouseStatus Status { get; internal set; } public virtual IList<IAccount> Accounts { get; internal set; } }

He ido por el camino del mapeo a las clases concretas. Todo está bien hasta que se crean relaciones que devuelven interfaces y se deben convertir en implementaciones concretas.

HasMany(x => x.Accounts)

puede llegar a ser

HasMany<Account>(x => x.Accounts)

Pero no hay un ''cast'' equivalente para

References(x => x.House)

El mapeo a las interfaces (la solución más ordenada) presenta el problema mencionado anteriormente en el sentido de que la identificación debe existir en la clase más alta para su configuración y requiere un configurador en la interfaz.

public sealed class AccountMap : ClassMap<IAccount> { public PokerPlayerMap() { Id(x => x.AccountId, "account_id"); DiscriminateSubClassesOnColumn("Type").SubClass<Account>(s => { References(x => x.House); }); } }

Por ahora, mi única solución es agregar configuradores a todos los campos de ID de interfaz. Es una pena que el ID no pueda existir dentro de una subclase o que su tipo se emita desde la interfaz.

Me han sumido y he empezado a aprender Fluido NHibernate (sin experiencia previa en NHibernate). En mi proyecto, estoy programando interfaces para reducir el acoplamiento, etc. Eso significa que casi todo se refiere a la interfaz en lugar del tipo concreto (mensaje en lugar de mensaje). La idea detrás de esto es ayudar a hacerlo más comprobable al poder simular las dependencias.

Sin embargo, (Fluido) a NHibernate no le encanta cuando trato de asignar interfaces en lugar de clases concretas. El problema es simple: según Fluent Wiki, es inteligente definir el campo de ID de mi clase como, por ejemplo,

int Id { get; private set; }

para obtener una clave primaria auto generada típica. Sin embargo, eso solo funciona con clases concretas: no puedo especificar un nivel de acceso en una interfaz, donde la misma línea debe ser

int Id { get; set; }

y supongo que eso niega que el establecedor sea privado en la clase concreta (la idea es que solo NHibernate debería establecer el ID como lo asignó el DB).

Por ahora, supongo que simplemente haré público a la colocadora e intentaré evitar la tentación de escribirle. Pero, ¿alguien tiene una idea de cuál sería la forma "adecuada" y la mejor práctica para crear una clave principal adecuada? ¿Campo en el que solo NHibernate puede escribir mientras aún solo está programando interfaces?

ACTUALIZADO

Por lo que entiendo después de las dos respuestas siguientes de mookid y James Gregory, puedo estar en el camino equivocado, no debería haber una razón para tener una interfaz por entidad como la que tengo ahora. Eso está muy bien. Supongo que mi pregunta es: ¿no hay razón para programar el 100% contra una interfaz para alguna entidad? Y si hay una sola situación en la que esto podría justificarse, ¿es posible hacerlo con NHibernate (Fluido)?

Lo pregunto porque no sé, para no ser crítico. Gracias por las respuestas. :)


Parece que no tengo suficiente reputación como para comentar las respuestas de otras personas, pero como tal voy a tener que hacer que esta sea una respuesta por derecho propio.

Las referencias ahora tienen una sobrecarga genérica para permitir el reparto que theGecko estaba buscando en su respuesta.


Puedes ajustar tu interfaz para que contenga solo un captador:

public interface ISomeEntity { int Id { get; } }

Su clase concreta también puede implementar un setter, y como está programando para sus interfaces, nunca llamará al setter "por accidente".

Si desea rechazar la configuración de la identificación incluso cuando tiene una referencia a una instancia concreta, puede abstenerse de implementar un configurador y luego permitir que NHibernate acceda al campo en lugar de a la propiedad. establece tu campo de identificación directamente en lugar de invocar la propiedad. Entonces podrías mapear la identificación de esta manera:

Id(e => e.Id).Access.AsCamelCaseField();

en cuyo caso, su propiedad de Id debe estar respaldada por un campo de id correspondiente. Hay más convenciones de nomenclatura, por ejemplo, si prefiere guiones bajos como prefijo de campo privado.


Me doy cuenta de que esto es un desvío, y no una respuesta a su pregunta (aunque creo que mookid lo tiene cubierto).

Realmente debe evaluar si las interfaces en las entidades de su dominio realmente proporcionan algo de valor; es raro encontrar una situación en la que realmente necesites hacer esto.

Por ejemplo: ¿Cómo es que la dependencia de IMessage menos acoplada que la de Message , cuando ambas (casi) sin duda comparten firmas idénticas? No deberías tener que burlarte de una entidad, porque es raro que tenga el comportamiento suficiente para requerir que te burlen de una entidad.


ACTUALIZACIÓN: el uso de union-subclass no es compatible a través de la interfaz fluida fluent-nhibernate proporciona. Tendrá que usar un archivo de mapeo hbm regular y agregarlo.

Yo también estoy tratando de hacer esto con un fluido NHibernate. No creo que deba ser un problema mapeando interfaces. Desea utilizar una estrategia de herencia, específicamente la estrategia de tabla por clase concreta .

Esencialmente, crea una definición de mapeo para la clase base (en este caso, su interfaz) y especifica cómo NHibernate debe tratar con los implementadores utilizando union-subclass.

Entonces, por ejemplo, esto debería permitirte hacer asociaciones polimórficas:

<class name="IAccountManager" abstract="true" table="IAccountManager"> <id name="Id"> <generator class="hilo"/> </id> <union-subclass table="DefaultAccountManager" name="DefaultAccountManager"> <property name="FirstName"/> </union-subclass> <union-subclass table="AnotherAccountManagerImplementation" name="AnotherAccountManagerImplementation"> <property name="FirstName"/> </union-subclass> ... </class>

Observe cómo el Id es el mismo para todos los implementadores concretos. NHibernate lo requería. Además, la tabla IAccountManager no existe realmente.

También puede probar y aprovechar el Polimorfismo implícito de NHibernate (documentado debajo de la estrategia de tabla por clase de concreto), pero tiene muchas limitaciones.