NHibernate多对多 [英] NHibernate Many To Many

查看:131
本文介绍了NHibernate多对多的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



投资组合和投资组合标签



投资组合项目可以有多个投资组合标签



我正在寻找将标签保存到投资组合项目的最佳方式。我的Nhibnerate贴图如下所示:

  public class PortfolioMap:ClassMap< Portfolio> {

公共投资组合图(){
表(投资组合);
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity()。Column(Id);
Map(x => x.AliasTitle).Column(AliasTitle)。Not.Nullable();
Map(x => x.MetaDescription).Column(MetaDescription)。Not.Nullable();
Map(x => x.Title).Column(Title)。Not.Nullable();
Map(x => x.Client).Column(Client)。Not.Nullable();
Map(x => x.Summary).Column(Summary)。Not.Nullable();
Map(x => x.Url).Column(Url);
Map(x => x.MainImage).Column(MainImage);
Map(x => x.TitleAlt).Column(TitleAlt);
Map(x => x.Description).Column(Description)。Not.Nullable();
HasMany(x => x.PortfolioImage).KeyColumn(PortfolioId)。Inverse();
HasMany(x => x.PortfolioTag).KeyColumn(PortfolioId)。Cascade.All()。Table(PortfolioTag)。Inverse();
}
}

public class PortfoliotagMap:ClassMap< Portfoliotag> {

public PortfoliotagMap(){
表(PortfolioTag);
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity()。Column(Id);
参考文献(x => x.Portfolio).Column(PortfolioId);
引用(x => x.Tag).Column(TagId);
}
}



公共类TagMap:ClassMap< Tag>
{

public TagMap(){
Table(Tag);
LazyLoad();
Id(x => x.TagId).GeneratedBy.Identity()。Column(TagId);
Map(x => x.TagVal).Column(Tag)。Not.Nullable();
HasManyToMany(x => x.Portfolio).Table(PortfolioTag)。ParentKeyColumn(TagId)。ChildKeyColumn(PortfolioId)。Inverse();




$ b在我的投资组合控制器中,我首先尝试保存我的不存在的标签。我试着在标签库上使用SaveOrUpdate。但是,由于id不同,所以在这一点上多次保存标签。



我想了一下以下的步骤,但看起来很长:



<1>获取所有标签:
var tags = _tagRepository.GetAll();
$ b <2>保存并查看它们是否存在于数据库中。如果是这样,我需要得到标签,并与投资组合项目相关联。如果没有,我将需要保存标签一个接一个,然后关联组合项目。

  var tags = _tagRepository.GetAll(); 

foreach(var tagInPortfolio在StringUtilities.SplitToList(model.Tags,new [] {','}))
{
//标记不存在,所以保存$ (tag.Any(i => i.TagVal == tagInPortfolio))
{
_tagRepository.SaveOrUpdate(new Tag {TagVal = tagInPortfolio});


$ / code $ / $ p

3)然后我需要删除任何关系ie标签投资组合不存在的项目。

4)最后需要添加标签到portfolioTag。我需要再次获得所有的标签,然后关联:

  portfolio.PortfolioTag.Add(new Portfoliotag {Portfolio = portfolio, Tag = tag}); 

_portfolioRepository.UpdateCommit(portfolio);

这似乎是漫长的啰嗦。任何人都可以解释这样做的最简单的方法请。

我已经看过saveandcommit标签,但我得到多个插入,因为ids是不同的。是否需要删除所有现有的标记关系,因为这似乎是很简单的逻辑。



现在创建一个提交 -

  public void CreateCommit(T entity)
{
using(ITransaction transaction = Session.BeginTransaction())
{
Session.Save(entity);
transaction.Commit();
}

}

但是使用下面和上面地图仍然意味着在标签表中发生的重复。所以如果一个投资组合记录添加了一个标签,如abc和另一个投资组合记录添加了一个标签abc,我需要连接表来引用标签中的相同记录,而不是创建另一个abc实例。为了避免这种情况,我需要在标签表上进行查找吗?

preublic $ UpdateCommit(T entity)
{
using(ITransaction transaction = Session.BeginTransaction())
{
Session.Update(entity);
transaction.Commit();



$ div $解析方案

如果我理解正确,我想你误解了多对多的映射。如果你真的在Portifolio和Tag类之间有这样的关系,你应该 not 映射PortfolioTag表。



用于连接其他两个主表的表应该只有两个表中的外键(这也是该中间表的组合键)。在这种情况下,PortfolioTag表将只有两列: PortfolioId TagId ,这不仅是投资组合和标签表的外键,而且还是主键在这种情况下,您的投资组合类应该有标签列表,而不是投资组合标签列表。 / em>,标签类是投资组合的列表。你应该像这样映射投资组合和标签(不需要映射中间表):

$ $ $ $ $ $ $ $ $ $ $ $>公共类投资组合映射:类映射<组合与GT; {
public PortfolioMap(){
表(投资组合);
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity()。Column(Id);
//
//代码为了清晰起见有意省略
//
HasManyToMany(x => x.Tags)
.Table(PortfolioTag)
.ParentKeyColumn(PortfolioId)
.ChildKeyColumn(TagId)
.LazyLoad()
.Cascade.SaveUpdate();


$ b $ public class TagMap:ClassMap< Tag> {
public TagMap(){
Table(Tag);
LazyLoad();
Id(x => x.Id).GeneratedBy.Identity()。Column(Id);
Map(x => x.TagVal).Column(Tag)。Not.Nullable();
HasManyToMany(x => x.Portfolio)
.Table(PortfolioTag)
.ParentKeyColumn(TagId)
.ChildKeyColumn(PortfolioId)
。反转();


$ / code $ / pre

您还必须在上下文中保存投资组合中间表的一个事务被填充,就像下面这样:

  using(var trans = Session.BeginTransaction()){ 
尝试{
Session.SaveOrUpdate(obj);
trans.Commit();
} catch {
trans.Rollback();
throw;



//或者像这样(使用TransactionScope)

使用(var trans = new TransactionScope()){
Session.SaveOrUpdate(OBJ);
trans.Complete();





$ b

通过这种方法,你也可以免于迭代标签列表保存每一个。 PS:我用 FluentNHibernate v1.4.0.0 测试了这个代码,所以你可以保存组合,一切都应该没有问题。

NHibernate v3.3.1.4000

I have a many to many relationship between

Portfolio and PortfolioTags

A portfolio Item can have many PortfolioTags

I am looking at the best way of saving tags to a portfolio item. My Nhibnerate maps are like so:

 public class PortfolioMap : ClassMap<Portfolio> {

        public PortfolioMap() {
            Table("Portfolio");
            LazyLoad();
            Id(x => x.Id).GeneratedBy.Identity().Column("Id");
            Map(x => x.AliasTitle).Column("AliasTitle").Not.Nullable();
            Map(x => x.MetaDescription).Column("MetaDescription").Not.Nullable();
            Map(x => x.Title).Column("Title").Not.Nullable();
            Map(x => x.Client).Column("Client").Not.Nullable();
            Map(x => x.Summary).Column("Summary").Not.Nullable();
            Map(x => x.Url).Column("Url");
            Map(x => x.MainImage).Column("MainImage");
            Map(x => x.TitleAlt).Column("TitleAlt");
            Map(x => x.Description).Column("Description").Not.Nullable();
            HasMany(x => x.PortfolioImage).KeyColumn("PortfolioId").Inverse();
            HasMany(x => x.PortfolioTag).KeyColumn("PortfolioId").Cascade.All().Table("PortfolioTag").Inverse();
        }
    }

public class PortfoliotagMap : ClassMap<Portfoliotag> {

    public PortfoliotagMap() {
        Table("PortfolioTag");
        LazyLoad();
        Id(x => x.Id).GeneratedBy.Identity().Column("Id");
        References(x => x.Portfolio).Column("PortfolioId");
        References(x => x.Tag).Column("TagId");
    }
}



 public class TagMap : ClassMap<Tag>
{

      public TagMap() {
        Table("Tag");
        LazyLoad();
        Id(x => x.TagId).GeneratedBy.Identity().Column("TagId");
        Map(x => x.TagVal).Column("Tag").Not.Nullable();
        HasManyToMany(x => x.Portfolio).Table("PortfolioTag").ParentKeyColumn("TagId").ChildKeyColumn("PortfolioId").Inverse();
    }
    }

In my portfolio controller I am first trying to save my tags that do not exist. I tried using SaveOrUpdate on a tag repository. However as the ids are different multiple save of tags occurs at this point.

I thought about the following steps but it seems long winded:

1) getting all tags: var tags = _tagRepository.GetAll();

2) Iterating over the tags from the item to save and seeing if they exist in the database. If so I would need to get the tag and associate with the portfolio item. If not i would need to save the tag one by one and then associate with the portfolio item.

        var tags = _tagRepository.GetAll();

        foreach (var tagInPortfolio in StringUtilities.SplitToList(model.Tags, new[] { ',' }))
        {
            // tag does not exist so save it
            if (tags.Any(i => i.TagVal == tagInPortfolio))
            {
                _tagRepository.SaveOrUpdate(new Tag {TagVal = tagInPortfolio});
            }
        }

3) I then need to delete any relationships i.e. tags to portfolio items that dont exist.

4) Finally need to add the tag to to the portfolioTag. I would need to get all the tags again and then associate:

  portfolio.PortfolioTag.Add(new Portfoliotag {Portfolio = portfolio, Tag = tag});

 _portfolioRepository.UpdateCommit(portfolio);

This seems to long winded. Can anyone explain the most simplest way of doing this please.

I have looked at saveandcommit on tags but i get multiple inserts because of ids being different. Do I need to delete all existing tag relationships also as this seems to much logic for something simple.

Create now works with a commit -

public void CreateCommit(T entity)
    {
        using (ITransaction transaction = Session.BeginTransaction())
        {
            Session.Save(entity); 
            transaction.Commit();
        }

    }

However using the below and the above maps still meant duplicates where occurring in the tag table. So if one portfolio record added a tag like abc and another portfolio record added a tag abc i need the join table to reference the same record in the tag and not create another instance of abc. Do i need to do a lookup on the tag table to avoid this

public void UpdateCommit(T entity)
        {
            using (ITransaction transaction = Session.BeginTransaction())
            {
                Session.Update(entity);
                transaction.Commit();
            }
        } 

解决方案

If I understood correctly, I think you misunderstood the many-to-many mapping. If you really have a relationship like this between the Portifolio and the Tag classes, you should not map the PortfolioTag table.

In a simple many-to-many relationship the table used to connect the other two main tables should have only the foreign keys from the two tables (that would also be a composite key of this intermediate table). In this case, the PortfolioTag table would have only two columns: PortfolioId and TagId, that would be not only foreign keys for the Portfolio and Tag tables, but also the primary key of this intermediate table.

In this case, your Portfolio class should have a list of Tags instead of a list of PortfolioTag, and the Tag class a list of Portfolios. And you should map the Portfolio and the Tag like this (with no need of mapping the intermediate table):

public class PortfolioMap : ClassMap<Portfolio> {
    public PortfolioMap() {
        Table("Portfolio");
        LazyLoad();
        Id(x => x.Id).GeneratedBy.Identity().Column("Id");
        //
        // Code intentionally omitted for clarity
        //
        HasManyToMany(x => x.Tags)
         .Table("PortfolioTag")
         .ParentKeyColumn("PortfolioId")
         .ChildKeyColumn("TagId")
         .LazyLoad()
         .Cascade.SaveUpdate();
    }
}

public class TagMap : ClassMap<Tag> {
    public TagMap() {
        Table("Tag");
        LazyLoad();
        Id(x => x.Id).GeneratedBy.Identity().Column("Id");
        Map(x => x.TagVal).Column("Tag").Not.Nullable();
        HasManyToMany(x => x.Portfolios)
         .Table("PortfolioTag")
         .ParentKeyColumn("TagId")
         .ChildKeyColumn("PortfolioId")
         .Inverse();
    }
}

You will also have to save the Portfolio inside the context of a transaction for the intermediate table to be populated, like bellow:

using (var trans = Session.BeginTransaction()) {
    try {
        Session.SaveOrUpdate(obj);
        trans.Commit();
    } catch {
        trans.Rollback();
        throw;
    }
}

//or like this (with TransactionScope)

using (var trans = new TransactionScope()) {
    Session.SaveOrUpdate(obj);
    trans.Complete();
}

With this approach, you would also be excused of the need to iterate through the Tags list to save each one. You would be able to just save the Portfolio and everything should be fine.

P.S.: I tested this code with FluentNHibernate v1.4.0.0 and NHibernate v3.3.1.4000.

这篇关于NHibernate多对多的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆