Главная > Programming > FluentNHibernate: один к одному

FluentNHibernate: один к одному

При описании модели предметной области по существующей БД можно запросто встретить отношение между объектами типа один к одному. К примеру это может быть пользователь и дополнительная информация о пользователе.
Особенность этого отношения заключается в том, что сущность UserDetails имеет ключ, которой является не только первичным ключем, но и ссылкой на родительскую запсь User, и соответсвенно равен идентификатору пользователя.
Вот схема таблиц БД:

Схема БД с отношением один к одному

Классы, описывающие сущности приведены на диаграмме ниже:

Классы

А вот код:

public class User
{
	public virtual int Id { get; set; }
	public virtual string Name { get; set; }
	public virtual UserDetails Details { get; set; }
}

public class UserDetails
{
	public virtual int Id { get; set; }
	public virtual User User { get; set; }
	public virtual string Address { get; set; }
}

Маппинги, которые у меня получились:

public class UserMap : ClassMap<User>
{
	public UserMap()
	{
		Id(x => x.Id).GeneratedBy.Native("SEQ_USER");
		Map(x => x.Name);
		HasOne(x => x.Details)
			.Cascade.All()
			.ForeignKey("UserDetails");
	}
}

public class UserDetailsMap : ClassMap<UserDetails>
{
	public UserDetailsMap()
	{
		Id(x => x.Id).GeneratedBy.Foreign("User");
		Map(x => x.Address);
		HasOne(x => x.User).Constrained();
	}
}

А теперь проверим, что мы намапили:

[Test]
public void CanInsertUser()
{
	var user = new User()
	{
		Name = "BatMan",
		Details = new UserDetails() { Address = "New Vasuki" }
	};
	user.Details.User = user;
	using (var tx = Session.BeginTransaction())
	{
		Session.Save(user);
		tx.Commit();
	}
	
	Session.Clear();
	
	var actual = Session.Get<User>(user.Id);
	
	Assert.That(actual, Is.Not.Null);
	Assert.That(actual.Details, Is.Not.Null);
}

Обратите внимание, что запись сущности необходимо проводить в транзакции, для того чтобы NHibernate сбросил свой внутренний буфер, и добавил в БД объект UserDetails (можно было бы просто вызвать Session.Flush). Иначе в БД попадет только пользователь, без дополнительной информации о себе. Кроме того, после сохранения объектов я очищаю сессию, для того чтобы запрос по идентфификатору сгенерировал select, иначе NHibernate возмет объект из кеша.
Выполнение это теста приводит к вставке в таблицы User UserDetails связанных записей:

INSERT INTO [User] (Name) 
	VALUES (@p0);
select SCOPE_IDENTITY();
    @p0 = 'BatMan'
INSERT INTO [UserDetails] (Address, Id) 
	VALUES (@p0, @p1);
    @p0 = 'New Vasuki', @p1 = 1

Выборка пользователя методом Get генерирует слудущий SQL:

SELECT
	user0_.Id as Id2_1_,
	user0_.Name as Name2_1_,
	userdetail1_.Id as Id1_0_,
	userdetail1_.Address as Address1_0_ 
FROM
	[User] user0_ 
left outer join
	[UserDetails] userdetail1_ 
		on user0_.Id=userdetail1_.Id 
WHERE
	user0_.Id=@p0;
@p0 = 1

Дополнительная информация:

Рубрики:Programming Метки: , ,
  1. Комментариев нет.
  1. No trackbacks yet.

Оставьте комментарий