Soporte de mapeo multi-a-uno para propiedades de navegación de componentes en Entity Developer

Este artículo explica y proporciona un ejemplo práctico de cómo se implementa la compatibilidad con las propiedades de navegación de componentes en Entity Developer para NHibernate.
El soporte para esta funcionalidad incluye la capacidad de desconectarse a un tipo complejo para una mayor reutilización no solo de las propiedades de la entidad escalar sino también de las propiedades de navegación seguidas de un mapeo de visualización completo en el nivel de mapeo de propiedad específico de la propiedad privada con un tipo igual a un tipo específico de entidad compleja.

Hay varias formas de mostrar las propiedades de navegación de los componentes en NHibernate:

  • Lotes a uno;
  • Uno a muchos;
  • el uno al otro;
  • Muchos a muchos.

En este artículo, veremos los más populares, es decir. visualización multi-a-uno de las propiedades de navegación de los componentes. No nos centraremos en los tipos de comparación de las propiedades de navegación de los componentes con muchos y entre sí, ya que estos tipos de visualización no son muy comunes, además, su uso y configuración difieren poco del ejemplo y, por lo tanto, son bastante comprensibles. El mapeo de muchos a muchos se analiza en detalle en el artículo "Compatibilidad con el mapeo de muchos a muchos" para las propiedades de navegación de componentes en Entity Developer.

Índice

    Mostrar sin ambigüedades las propiedades de navegación de los componentes

    Este tipo de asignación puede ser efectivo si hay varias tablas en la base de datos que hacen referencia a una tabla de una sola parte mediante una restricción de clave externa y posiblemente (pero no necesariamente) con algún conjunto de campos que coincidan en valor y estructura. O la misma tabla contiene varios conjuntos de campos o claves foráneas de estructura similar, que describen varios objetos de datos de estructura similar, por ejemplo (por ejemplo, si la misma tabla que contiene una descripción de empresas incluye varios conjuntos coincidentes de campos que representan direcciones de cabeza y envío oficinas).

    Luego, después de crear el modelo, tiene sentido mover un conjunto similar de propiedades escalares y de navegación correspondientes a un tipo complejo separado y reemplazar cada conjunto con esencialmente una propiedad que tenga un tipo igual al tipo complejo, y el mapeo privado apropiado. ajuste para esa propiedad.

    Ejemplo:

    La base de datos contiene las tablas "Pedidos" y "Proveedores", que tienen una restricción de claves foráneas con la tabla "Países". Las tablas "Pedidos" y "Proveedores" tienen los mismos campos que contienen la descripción de la dirección, así como la columna de clave externa asociada con la tabla que contiene los nombres de los países con restricciones extranjeras.

    El script para crear tablas para DBMS de SQL Server tiene este aspecto:

    CREATE SCHEMA ManyToOne;
    GO
    
    CREATE TABLE ManyToOne.Countries (
      CountryID int,
      CountryName nvarchar(15) COLLATE Cyrillic_General_CI_AS NOT NULL,
      CONSTRAINT PK_Countries PRIMARY KEY (CountryID)
    )
    GO
    
    CREATE TABLE ManyToOne.Orders (
      OrderID int IDENTITY,
      Customer nvarchar(50) COLLATE Cyrillic_General_CI_AS Not NULL,
      Employee nvarchar(50) COLLATE Cyrillic_General_CI_AS Not NULL,
      OrderDate datetime NULL,
      RequiredDate datetime NULL,
      ShippedDate datetime NULL,
      Freight money NULL CONSTRAINT DF_Orders_Freight DEFAULT ((0)),
      ShipName nvarchar(40) COLLATE Cyrillic_General_CI_AS NULL,
      ShipAddress nvarchar(60) COLLATE Cyrillic_General_CI_AS NULL,
      ShipCity nvarchar(15) COLLATE Cyrillic_General_CI_AS NULL,
      ShipRegion nvarchar(15) COLLATE Cyrillic_General_CI_AS NULL,
      ShipPostalCode nvarchar(10) COLLATE Cyrillic_General_CI_AS NULL,
      ShipCountryID int NULL,
      CONSTRAINT PK_Orders PRIMARY KEY (OrderID),
      CONSTRAINT FK_Orders_Countries FOREIGN KEY (ShipCountryID) REFERENCES ManyToOne.Countries (CountryID)
    )
    GO
    
    CREATE TABLE ManyToOne.Suppliers (
      SupplierID int IDENTITY,
      CompanyName nvarchar(40) COLLATE Cyrillic_General_CI_AS NOT NULL,
      ContactName nvarchar(30) COLLATE Cyrillic_General_CI_AS NULL,
      ContactTitle nvarchar(30) COLLATE Cyrillic_General_CI_AS NULL,
      Address nvarchar(60) COLLATE Cyrillic_General_CI_AS NULL,
      City nvarchar(15) COLLATE Cyrillic_General_CI_AS NULL,
      Region nvarchar(15) COLLATE Cyrillic_General_CI_AS NULL,
      PostalCode nvarchar(10) COLLATE Cyrillic_General_CI_AS NULL,
      CountryID int NULL,
      Phone nvarchar(24) COLLATE Cyrillic_General_CI_AS NULL,
      Fax nvarchar(24) COLLATE Cyrillic_General_CI_AS NULL,
      HomePage ntext COLLATE Cyrillic_General_CI_AS NULL,
      CONSTRAINT PK_Suppliers PRIMARY KEY (SupplierID),
      CONSTRAINT FK_Suppliers_Countries FOREIGN KEY (CountryID) REFERENCES ManyToOne.Countries (CountryID)
    )

    El gráfico de la tabla se ve así:

    diagrama de base de datos

    Realice la siguiente secuencia de operaciones:

    • crear un modelo NHibernate;
    • agregue "Pedidos", "Proveedores" y "Países" al modelo.

    Antes de definir un tipo complejo, el modelo se ve así:

    El modelo inicial

    Seleccionamos la propiedad de navegación Dirección, Ciudad, Región, Código postal y País del objeto Proveedor utilizado para describir la dirección, los arrastramos a un tipo complejo separado y lo nombramos "Tipo de dirección"; hay una conexión entre este tipo complejo y la clase Country, y de ahora en adelante es un tipo AddressType complejo que contiene una propiedad de navegación de país, y en lugar de un conjunto de campos movidos, la entidad Provider contiene una propiedad con un tipo igual a AddressType, vamos a llámalo una dirección.

    La relación entre AddressType y el objeto Country es la siguiente:

    La ventana Editor de asociaciones para la asociación.

    Como se puede ver desde Redactor de la Asociación cuadro de diálogo, parte de la configuración de la relación está en la propia asociación, para el caso de muchos a uno también hay una asignación predeterminada para la columna de clave externa del asunto, que contendrá la propiedad del tipo complejo especificado, pero si es necesario puede cambiarse a personalizado para una propiedad específica. Esto se mostrará en nuestro ejemplo más adelante en este artículo.

    Debido a que creamos un tipo complejo basado en un conjunto de propiedades de entidad de proveedor, la asignación personalizada de estas propiedades se determinó automáticamente para este objeto y se ve así:

    Propiedades de asignación personalizadas

    Ahora debe eliminar el enlace entre los objetos Pedido y País, así como eliminar las propiedades de ShipAddress, ShipCity, ShipRegion, ShipPostalCode del objeto Order. En lugar de un conjunto de estas propiedades que describen la dirección de la empresa del propietario del barco, debe agregar una propiedad con el nombre 'ShipAddress' y un tipo igual a AddressType. Dado que los nombres de las columnas de descripción y las columnas externas del pedido no coinciden con la visualización predeterminada del tipo complejo AddressType y la visualización predeterminada de la columna de asociación externa, debe especificar una visualización personalizada para el objeto de pedido ShipAddress. propiedad de estas columnas como se muestra a continuación:

    Visualización personalizada de las propiedades de ShipAddress

    Como resultado, tenemos el siguiente modelo:

    el modelo definitivo

    El código generado para el modelo es el siguiente:

        /// <summary>
        /// There are no comments for AddressType in the schema.
        /// </summary>
        public partial class AddressType {
            private string _Address;
            private string _City;
            private string _Region;
            private string _PostalCode;
            private Country _Country;    
            #region Extensibility Method Definitions        
            partial void OnCreated();        
            #endregion
            public AddressType()
            {
                OnCreated();
            }    
            /// <summary>
            /// There are no comments for Address in the schema.
            /// </summary>
            public virtual string Address
            {
                get
                {
                    return this._Address;
                }
                set
                {
                    this._Address = value;
                }
            }    
            /// <summary>
            /// There are no comments for City in the schema.
            /// </summary>
            public virtual string City
            {
                get
                {
                    return this._City;
                }
                set
                {
                    this._City = value;
                }
            }    
            /// <summary>
            /// There are no comments for Region in the schema.
            /// </summary>
            public virtual string Region
            {
                get
                {
                    return this._Region;
                }
                set
                {
                    this._Region = value;
                }
            }    
            /// <summary>
            /// There are no comments for PostalCode in the schema.
            /// </summary>
            public virtual string PostalCode
            {
                get
                {
                    return this._PostalCode;
                }
                set
                {
                    this._PostalCode = value;
                }
            }    
            /// <summary>
            /// There are no comments for Country in the schema.
            /// </summary>
            public virtual Country Country
            {
                get
                {
                    return this._Country;
                }
                set
                {
                    this._Country = value;
                }
            }
        }
        /// <summary>
        /// There are no comments for Country in the schema.
        /// </summary>
        public partial class Country {
            private int _CountryID;
            private string _CountryName;    
            #region Extensibility Method Definitions        
            partial void OnCreated();        
            #endregion
            public Country()
            {
                OnCreated();
            }    
            /// <summary>
            /// There are no comments for CountryID in the schema.
            /// </summary>
            public virtual int CountryID
            {
                get
                {
                    return this._CountryID;
                }
                set
                {
                    this._CountryID = value;
                }
            }    
            /// <summary>
            /// There are no comments for CountryName in the schema.
            /// </summary>
            public virtual string CountryName
            {
                get
                {
                    return this._CountryName;
                }
                set
                {
                    this._CountryName = value;
                }
            }
        }
        /// <summary>
        /// There are no comments for Supplier in the schema.
        /// </summary>
        public partial class Supplier {
            private int _SupplierID;
            private string _CompanyName;
            private string _ContactName;
            private string _ContactTitle;
            private string _Phone;
            private string _Fax;
            private string _HomePage;
            private AddressType _Address;    
            #region Extensibility Method Definitions        
            partial void OnCreated();        
            #endregion
            public Supplier()
            {
                this._Address = new AddressType();
                OnCreated();
            }    
            /// <summary>
            /// There are no comments for SupplierID in the schema.
            /// </summary>
            public virtual int SupplierID
            {
                get
                {
                    return this._SupplierID;
                }
                set
                {
                    this._SupplierID = value;
                }
            }    
            /// <summary>
            /// There are no comments for CompanyName in the schema.
            /// </summary>
            public virtual string CompanyName
            {
                get
                {
                    return this._CompanyName;
                }
                set
                {
                    this._CompanyName = value;
                }
            }    
            /// <summary>
            /// There are no comments for ContactName in the schema.
            /// </summary>
            public virtual string ContactName
            {
                get
                {
                    return this._ContactName;
                }
                set
                {
                    this._ContactName = value;
                }
            }    
            /// <summary>
            /// There are no comments for ContactTitle in the schema.
            /// </summary>
            public virtual string ContactTitle
            {
                get
                {
                    return this._ContactTitle;
                }
                set
                {
                    this._ContactTitle = value;
                }
            }    
            /// <summary>
            /// There are no comments for Phone in the schema.
            /// </summary>
            public virtual string Phone
            {
                get
                {
                    return this._Phone;
                }
                set
                {
                    this._Phone = value;
                }
            }    
            /// <summary>
            /// There are no comments for Fax in the schema.
            /// </summary>
            public virtual string Fax
            {
                get
                {
                    return this._Fax;
                }
                set
                {
                    this._Fax = value;
                }
            }    
            /// <summary>
            /// There are no comments for HomePage in the schema.
            /// </summary>
            public virtual string HomePage
            {
                get
                {
                    return this._HomePage;
                }
                set
                {
                    this._HomePage = value;
                }
            }    
            /// <summary>
            /// There are no comments for Address in the schema.
            /// </summary>
            public virtual AddressType Address
            {
                get
                {
                    return this._Address;
                }
                set
                {
                    this._Address = value;
                }
            }
        }
        /// <summary>
        /// There are no comments for Order in the schema.
        /// </summary>
        public partial class Order {
            private int _OrderID;
            private string _Customer;
            private string _Employee;
            private System.Nullable<System.DateTime> _OrderDate;
            private System.Nullable<System.DateTime> _RequiredDate;
            private System.Nullable<System.DateTime> _ShippedDate;
            private System.Nullable<decimal> _Freight;
            private string _ShipName;
            private AddressType _ShipAddress;    
            #region Extensibility Method Definitions        
            partial void OnCreated();        
            #endregion
            public Order()
            {
                this._ShipAddress = new AddressType();
                OnCreated();
            }    
            /// <summary>
            /// There are no comments for OrderID in the schema.
            /// </summary>
            public virtual int OrderID
            {
                get
                {
                    return this._OrderID;
                }
                set
                {
                    this._OrderID = value;
                }
            }    
            /// <summary>
            /// There are no comments for Customer in the schema.
            /// </summary>
            public virtual string Customer
            {
                get
                {
                    return this._Customer;
                }
                set
                {
                    this._Customer = value;
                }
            }    
            /// <summary>
            /// There are no comments for Employee in the schema.
            /// </summary>
            public virtual string Employee
            {
                get
                {
                    return this._Employee;
                }
                set
                {
                    this._Employee = value;
                }
            }    
            /// <summary>
            /// There are no comments for OrderDate in the schema.
            /// </summary>
            public virtual System.Nullable<System.DateTime> OrderDate
            {
                get
                {
                    return this._OrderDate;
                }
                set
                {
                    this._OrderDate = value;
                }
            }    
            /// <summary>
            /// There are no comments for RequiredDate in the schema.
            /// </summary>
            public virtual System.Nullable<System.DateTime> RequiredDate
            {
                get
                {
                    return this._RequiredDate;
                }
                set
                {
                    this._RequiredDate = value;
                }
            }    
            /// <summary>
            /// There are no comments for ShippedDate in the schema.
            /// </summary>
            public virtual System.Nullable<System.DateTime> ShippedDate
            {
                get
                {
                    return this._ShippedDate;
                }
                set
                {
                    this._ShippedDate = value;
                }
            }    
            /// <summary>
            /// There are no comments for Freight in the schema.
            /// </summary>
            public virtual System.Nullable<decimal> Freight
            {
                get
                {
                    return this._Freight;
                }
                set
                {
                    this._Freight = value;
                }
            }    
            /// <summary>
            /// There are no comments for ShipName in the schema.
            /// </summary>
            public virtual string ShipName
            {
                get
                {
                    return this._ShipName;
                }
                set
                {
                    this._ShipName = value;
                }
            }    
            /// <summary>
            /// There are no comments for ShipAddress in the schema.
            /// </summary>
            public virtual AddressType ShipAddress
            {
                get
                {
                    return this._ShipAddress;
                }
                set
                {
                    this._ShipAddress = value;
                }
            }
        }

    Como se puede ver en el código generado, la clase AddressType genera una propiedad que contiene una referencia a la clase Country, y las clases Order y Supplier, a su vez, contienen una propiedad con un tipo igual a AddressType, y estas propiedades describen el envío. dirección de la empresa y del proveedor respectivamente.

    El mapeo Xml creado para el modelo se ve así:

    <hibernate-mapping namespace="testmodellerModel" xmlns="urn:nhibernate-mapping-2.2">
      <class name="Supplier" table="Suppliers" schema="ManyToOne">
        <id name="SupplierID" type="Int32">
          <column name="SupplierID" not-null="true" precision="10" scale="0" sql-type="int" />
          <generator class="identity" />
        </id>
        <property name="CompanyName" type="String">
          <column name="CompanyName" not-null="true" length="40" sql-type="nvarchar" />
        </property>
        <property name="ContactName" type="String">
          <column name="ContactName" not-null="false" length="30" sql-type="nvarchar" />
        </property>
        <property name="ContactTitle" type="String">
          <column name="ContactTitle" not-null="false" length="30" sql-type="nvarchar" />
        </property>
        <property name="Phone" type="String">
          <column name="Phone" not-null="false" length="24" sql-type="nvarchar" />
        </property>
        <property name="Fax" type="String">
          <column name="Fax" not-null="false" length="24" sql-type="nvarchar" />
        </property>
        <property name="HomePage" type="StringClob">
          <column name="HomePage" not-null="false" length="1073741823" sql-type="ntext" />
        </property>
        <component name="Address" class="AddressType">
          <property name="Address" type="String">
            <column name="Address" not-null="false" length="60" sql-type="nvarchar" />
          </property>
          <property name="City" type="String">
            <column name="City" not-null="false" length="15" sql-type="nvarchar" />
          </property>
          <property name="Region" type="String">
            <column name="Region" not-null="false" length="15" sql-type="nvarchar" />
          </property>
          <property name="PostalCode" type="String">
            <column name="PostalCode" not-null="false" length="10" sql-type="nvarchar" />
          </property>
          <many-to-one name="Country" class="Country">
            <column name="CountryID" not-null="false" precision="10" scale="0" sql-type="int" />
          </many-to-one>
        </component>
      </class>
      <class name="Order" table="Orders" schema="ManyToOne">
        <id name="OrderID" type="Int32">
          <column name="OrderID" not-null="true" precision="10" scale="0" sql-type="int" />
          <generator class="identity" />
        </id>
        <property name="Customer" type="String">
          <column name="Customer" not-null="true" length="50" sql-type="nvarchar" />
        </property>
        <property name="Employee" type="String">
          <column name="Employee" not-null="true" length="50" sql-type="nvarchar" />
        </property>
        <property name="OrderDate" type="DateTime">
          <column name="OrderDate" not-null="false" sql-type="datetime" />
        </property>
        <property name="RequiredDate" type="DateTime">
          <column name="RequiredDate" not-null="false" sql-type="datetime" />
        </property>
        <property name="ShippedDate" type="DateTime">
          <column name="ShippedDate" not-null="false" sql-type="datetime" />
        </property>
        <property name="Freight" type="Decimal">
          <column name="Freight" default="0" not-null="false" precision="19" scale="4" sql-type="money" />
        </property>
        <property name="ShipName" type="String">
          <column name="ShipName" not-null="false" length="40" sql-type="nvarchar" />
        </property>
        <component name="ShipAddress" class="AddressType">
          <property name="Address" type="String">
            <column name="ShipAddress" not-null="false" length="60" sql-type="nvarchar" />
          </property>
          <property name="City" type="String">
            <column name="ShipCity" not-null="false" length="15" sql-type="nvarchar" />
          </property>
          <property name="Region" type="String">
            <column name="ShipRegion" not-null="false" length="15" sql-type="nvarchar" />
          </property>
          <property name="PostalCode" type="String">
            <column name="ShipPostalCode" not-null="false" length="10" sql-type="nvarchar" />
          </property>
          <many-to-one name="Country" class="Country">
            <column name="ShipCountryID" not-null="true" precision="10" scale="0" sql-type="int" />
          </many-to-one>
        </component>
      </class>
      <class name="Country" table="Countries" schema="ManyToOne">
        <id name="CountryID" type="Int32">
          <column name="CountryID" not-null="true" precision="10" scale="0" sql-type="int" />
          <generator class="assigned" />
        </id>
        <property name="CountryName" type="String">
          <column name="CountryName" not-null="true" length="15" sql-type="nvarchar" />
        </property>
      </class>
    </hibernate-mapping>

    El modelo NHibernate para Entity Developer creado en este ejemplo se puede descargar aquí

    Artículos de interés

    Subir