Как сопоставить сущность как свойство класса другой сущности, используя сопоставление по коду (NHibernate)
Я хочу, чтобы текстовые свойства моего объекта сохранялись на нескольких языках. Для этого я просто хочу сохранить FK в таблице TextContent (которая в основном содержит только ключ) и в отдельной таблице перевода, которая содержит строку для каждого перевода.
Вот моя модель базы данных
И мои соответствующие сущности
public sealed class Translation : IEquatable<Translation>
{
public static bool operator ==(Translation left, Translation right) => Equals(left, right);
public static bool operator !=(Translation left, Translation right) => !Equals(left, right);
// ORM-only constructor
private Translation() { }
public Translation(int languageId, string text)
{
_language = languageId;
_text = text;
}
public bool Equals(Translation other) ...
public override bool Equals(object obj) ...
public override int GetHashCode() ...
public int LanguageId => _language;
public string Text => _text;
private readonly int _languageId;
private readonly string _text;
}
public class TextContent
{
// ORM-only constructor
protected TextContent() { }
public TextContent(int Id, List<Translation> translations)
{
_id = Id;
_originalLanguage = translations.First().LanguageId;
_originalText = translations.First().Text;
_translations = translations;
}
public virtual int Id => _id;
public virtual int OriginalLanguageId => _originalLanguage;
public virtual string OriginalText => _originalText;
public virtual IList<Translation> Translations => _translations;
private readonly int _id;
private readonly int _originalLanguageId;
private readonly string _originalText;
private readonly IList<Translation> _translations;
}
public partial class Product
{
// ORM-only constructor
protected Product() { }
public Product(int Id, TextContent name, TextContent description)
{
_id = Id;
_nameId = name.Id;
_name = name;
_descriptionId = description.Id;
_description = description;
}
public virtual int Id => _id;
public virtual TextContent Name => _name;
public virtual TextContent Description => _description;
private int _id;
private int _nameId;
private TextContent _name;
private int _descriptionId;
private TextContent _description;
}
Сопоставления, которые я пробовал
public class TextContentMapping : ClassMapping<TextContent>
{
public TextContentMapping()
{
Table("TextContent");
Id(content => content.Id);
Property(content => content.OriginalLanguage);
Property(content => content.OriginalText);
Bag(
content => content.Translations,
mapper =>
{
mapper.Table(nameof(Translation));
mapper.Cascade(Cascade.All);
mapper.Key(
keyMapper =>
{
keyMapper.Column(columnMapper => columnMapper.Name("TextContentId"));
keyMapper.NotNullable(true);
});
},
relation => relation.Component(
mapper =>
{
mapper.Property(translation => translation.LanguageId);
mapper.Property(translation => translation.Text);
}));
}
}
public class ProductMapping : ClassMapping<Product>
{
public ProductMapping()
{
Table(nameof(Product));
Id(product=> product.Id, mapper => mapper.Access(Accessor.Field));
Property(
"_nameId",
mapper =>
{
mapper.Column("NameId");
mapper.Access(Accessor.Field);
mapper.NotNullable(true);
});
Property(
"_descriptionId",
mapper =>
{
mapper.Column("DescriptionId");
mapper.Access(Accessor.Field);
mapper.NotNullable(true);
});
OneToOne(
product => product.Name,
mapper =>
{
mapper.Constrained(true);
mapper.Cascade(Cascade.All);
mapper.Access(Accessor.Field);
mapper.Class(typeof(TextContent));
});
OneToOne(
product => product.Description,
mapper =>
{
mapper.Constrained(true);
mapper.Cascade(Cascade.All);
mapper.Access(Accessor.Field);
mapper.Class(typeof(TextContent));
});
}
}
Как вы можете догадаться, вставка работает, а выбор - нет, поскольку мое текущее сопоставление не обеспечивает связь между_nameId
иTextContent Name
сущность ? Есть ли способ сделать это? Если нет, то какие сопоставления и объекты предметной области будут лучше, соответствующие моей модели базы данных?
1 ответ
Сопоставление OneToOne — это когда у другой стороны есть внешний ключ. Это должно быть ManyToOne. Использование этих классов
public class TextContent
{
// ORM-only constructor
protected TextContent() { }
public TextContent(int languageId, string text) : this()
{
OriginalLanguageId = languageId;
OriginalText = text;
Translations = new Dictionary<int, string>();
}
public virtual int Id { get; protected set; }
public virtual int OriginalLanguageId { get; protected set; }
public virtual string OriginalText { get; protected set; }
public virtual IDictionary<int, string> Translations { get; protected set; }
}
public class Product
{
// ORM-only constructor
protected Product() { }
public Product(TextContent name, TextContent description)
{
Name = name;
Description = description;
}
public virtual int Id { get; protected set; }
public virtual TextContent Name { get; protected set; }
public virtual TextContent Description { get; protected set; }
}
и эти отображения
public class TextContentMapping : ClassMapping<TextContent>
{
public TextContentMapping()
{
Table("TextContent");
Id(content => content.Id, m => m.Generator(Generators.Native));
Property(content => content.OriginalLanguageId);
Property(content => content.OriginalText);
Map(
content => content.Translations,
mapper =>
{
mapper.Table("Translation");
mapper.Cascade(Cascade.All);
mapper.Key(
keyMapper =>
{
keyMapper.Column(columnMapper => columnMapper.Name("TextContentId"));
keyMapper.NotNullable(true);
});
},
keymapping => keymapping.Element(m => m.Column("LanguageId")),
elementMapping => elementMapping.Element(m => m.Column("Text"))
);
}
}
public class ProductMapping : ClassMapping<Product>
{
public ProductMapping()
{
Table(nameof(Product));
Id(product => product.Id, m => m.Generator(Generators.Native));
ManyToOne(
product => product.Name,
mapper =>
{
mapper.Column("NameId");
mapper.Cascade(Cascade.All);
mapper.NotNullable(true);
});
ManyToOne(
product => product.Description,
mapper =>
{
mapper.Column("DescriptionId");
mapper.Cascade(Cascade.All);
mapper.NotNullable(true);
});
}
}
следующий код работает
session.Save(new Product(new TextContent(1, "someText") { Translations = { { 2, "translated Text" } } }, new TextContent(1, "some description")));
session.Flush();
session.Clear();
var p = session.Query<Product>().ToList();
var s = p[0].Name.Translations[2];