2015-05-01 4 views
6

Я новичок в NHibernate и C#, поэтому, пожалуйста, будьте нежны!Минимальный и правильный способ сопоставления «один ко многим» с NHibernate

У меня есть следующие два NHibernate лица:

Employee 
{ 
    private long _id; 
    private String _name; 
    private String _empNumber; 
    private IList<Address> _addresses; 

    //Properties... 
} 

и

Address 
{ 
    private long _id; 
    private String _addrLine1; 
    private String _addrLine2; 
    private String _city; 
    private String _country; 
    private String _postalCode; 

    //Properties 
} 

и они имеют one-to-many отношения с Employee к Address(каждый сотрудник может иметь несколько адресов в их записи). Удобно игнорировать тот факт, что более одного сотрудника могут проживать по тому же адресу.

Я понимаю это с точки зрения объектов в памяти (объекты NHibernate ). То, с чем я борюсь, это файлы сопоставления (и я принимаю здесь ). Это то, что я придумал до сих пор:

// Intentionally left out XML and <hibernate-mapping> 
// Mappings for class 'Employee'. --> 
<class name="Employee" table="Employees"> 
    <id name="ID"> 
     <generator class="native"> 
    </id> 

    <property name="Name" /> 
    <property name="EmpNumber" /> 

    <bag name="Addresses"> 
     <key column="AddressId" /> 
     <one-to-many class="Address" /> 
    </bag> 
</class> 

и

// Intentionally left out XML and <hibernate-mapping> . 
// Mappings for class 'Address' 
<class name="Address" table="Addresses"> 
    <id name="ID"> 
     <generator class="native"> 
    </id> 

    // Intentionally left out name="Employee" 
    // as I don't have corresponding field in Address entity. 
    <many-to-one class="Employee" column="EmployeeID" cascade="all" /> 

    <property name="AddrLine1" /> 
    <property name="AddrLine2" /> 
    <property name="City" /> 
    <property name="Country" /> 
    <property name="PostalCode" /> 
</class> 
  1. Правильно ли это?
  2. Если нет, мне кажется, что здесь отсутствует поле в объекте Address , который является ссылкой на соответствующий объект Employee. Но если так, то я не могу понять, почему это необходимо: Мне не нужно, чтобы принести в Address из Employee, только наоборот ...
+0

Мне кажется, что вам нужно много-много отношений здесь, а не один ко многим, если адреса уникальны в адресной таблице. Это означало бы много-много таблиц, в которых хранится идентификатор сотрудника и идентификатор адреса. Таким образом, сотрудник может быть связан с одним или несколькими адресами, и адрес может принадлежать более чем одному сотруднику. –

+0

@ColeW Я не хочу, чтобы адреса принадлежали нескольким сотрудникам. Это преднамеренно. – markvgti

+0

Если это так, вам нужно будет добавить идентификатор сотрудника в таблицу адресов, чтобы определить, какие адреса принадлежат тем сотрудникам. Таким образом, в таблице адресов могут присутствовать несколько адресов с одинаковым идентификатором сотрудника. Вот как nhibernate будет знать, как заполнить 'private IList

_addresses;' в объекте 'Employee'. Я также предлагаю, чтобы у вас был объект «Сотрудник» как часть объекта «Адрес», так как навигацию по обеим сторонам отношения часто пригодится, даже если это не обязательно имеет смысл с точки зрения бизнес-логики все время. –

ответ

6

Просто несколько советов, обобщающее наиболее подходящие стандарты я обнаруживаемые при работе с NHibernate.

1) Если есть двунаправленный ссылка в persitence (колонка DB), выразить это в коде C#двунаправленным, а также.

Другими словами, если ребенок имеет отношение к родителей, родителя должны иметь ссылку на ребенка.

public class Employee 
{ 
    ... 
    public virtual IList<Address> { get; set; } 
} 
public class Address 
{ 
    ... 
    public virtual Employee Employee { get; set; } 
} 

Это бизнес-домен, как есть. Адрес принадлежит Employee and Employee принадлежит адресу.

Если мы по каким-то причинам действительно хотите ограничить, что мы должны скорее protected модификатор, но все же сохранить ссылку в C#

2) Используйте inverse="true". Это может быть использовано только тогда, когда мы нанесем обе стороны (как описано выше), и приведет к более «ожидаемый и оптимизированному» INSERT и UPDATE scritps

Подробнее здесь:

inverse = “true” example and explanation по mkyong

3) Использовать картографирование выборки партии почти всегда. Это позволит избежать проблем с 1 + N во время запросов. Подробнее:

few details about batch fetching

4) В случае, что один объект (in our case Employee) является root(другой не делает так много смысла без него) - использовать каскадные. Подробнее:

nhibernate - Create child by updating parent, or create explicitly?

Правило 2,3,4 в отображении фрагментов:

<class name="Employee" ... batch-size="25"> 
    ... 
    <bag name="Addresses" 
     lazy="true" 
     inverse="true" 
     batch-size="25" 
     cascade="all-delete-orphan" > 
    // wrong! This columns is the same as for many-to-one 
    //<key column="AddressId" /> 
    // it is the one column expressing the relation 
    <key column="EmployeeId" /> 
    <one-to-many class="Address" /> 
    </bag> 

<class name="Address" ... batch-size="25"> 
    ... 
    <many-to-one not-null="true" name="Employee" column="EmployeeID" /> 

3), если мы используем inverse="true не забудьте установить обе стороны отношения (в основном критического во время создание)

причина заключается в том:

мы инструктируем NHibernate - с другой стороны (Address) несет ответственность за сохраняющееся отношение. Но для этого достаточно, чтобы Address нуждался в ссылке на Employee - чтобы сохранить свой идентификатор в своем столбце в таблице адресов.

Так что это должно быть стандартный код, чтобы создать новый адрес электронной

Employee employee = ... // load or create new 
Address address = new Address 
{ 
    ... 
    Employee = employee, // this is important 
}; 
Employee.Addresses.Add(address); 
session.SaveOrUpdate(employee); // cascade will trigger the rest 

можно также ввести некоторый метод как AddAddress() который будет скрывать эту сложность, но установка обеих сторон является хорошим prectice.

+0

Работает ли NHibernate точно так же с C#, как Hibernate с Java? Я прошу, потому что статья о mkyong.com о 'inverse =" true "' использует примеры Java. – markvgti

+0

Этот фрагмент кода тот же (был перенесен с Java на C#). Самым важным является «дух обратного». Таким образом, даже если бы были небольшие различия, концепция такая же. Надеюсь, это поможет;) Наслаждайтесь могучим NHibernate;) –

1

Вы должны добавить каскад all-delete-orphan в отношении one-to-many, если вы удалите Employee, адрес также будет удален.

Если вам не нужна Employee ссылки создать inverse=false отношение так: here