HasMany关系导致"找到对集合的共享引用"从db读取时

时间:2015-05-11 08:54:34

标签: nhibernate fluent-nhibernate

我是NHibernate的新手,遇到映射问题。我没有谷歌回答。

我的实体看起来像这样:

public class Triage
{
    public virtual Guid Id { get; set; }

    public virtual IDictionary<int, Discriminator> Discriminators { get; set; }

    // This is to keep FluentNHibernate happy
    public virtual int? SelectedDiscriminatorId { get; set; }
}

public class Discriminator
{
    public virtual int Id { get; set; }
    public virtual int LanguageId { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as Discriminator;
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;

        return Id == other.Id && LanguageId == other.LanguageId;
    }

    public override int GetHashCode()
    {
        return new { Id, LanguageId }.GetHashCode();
    }
}

我的映射看起来像这样:

public class TriageMap : ClassMap<Triage>
{
    public TriageMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();
        HasMany(x => x.Discriminators)
            .KeyColumn("Id")
            .PropertyRef("SelectedDiscriminatorId")
            .Inverse()
            .Cascade.All()
            .Not.LazyLoad()
            .AsMap(x => x.LanguageId);

        // This mapping is only needed to keep FluentNHibernate happy...
        Map(x => x.SelectedDiscriminatorId);
    }
}

public class DiscriminatorMap : ClassMap<Discriminator>
{
    public DiscriminatorMap()
    {
        CompositeId()
            .KeyProperty(x => x.Id)
            .KeyProperty(x => x.LanguageId);
    }
}

想法是Triage有一个选择的Discriminator(SelectedDiscriminatorId),Discriminator-table包含几种可用语言的描述文本。并不特别喜欢Triage所指的Discriminator与SelectedDiscriminatorId的结构,它只是Discriminator(Id和LanguageId)中复合键的一部分,但这就是我的数据库的外观。

所以,当我像这样取得我的分数时:

_sessionFactory = CreateSessionFactory();
ISession session = _sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
var triages = _sessionFactory
    .GetCurrentSession()
    .Query<Triage>()
    .Fetch(t => t.Discriminators)
    .ToList();
session.Flush();
session.Close();
CurrentSessionContext.Unbind(_sessionFactory);

然后一切正常,条件是SelectedDiscriminatorId在获取的分类中是唯一的。但是,当有几个具有相同SelectedDiscriminatorId的分类时,我得到一个HibernateException说&#34;附加信息:找到对集合的共享引用:TestProject.Triage.Discriminators&#34;当它执行session.Flush()语句时。

知道这里有什么问题以及我如何纠正错误?感谢。

这是数据库的外观:

CREATE TABLE [dbo].[Triage](
    [Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF_Triage_Id]  DEFAULT (newid()),
    [SelectedDiscriminatorId] [int] NULL,
 CONSTRAINT [PK_Triage] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[Discriminator](
    [ID] [int] NOT NULL,
    [DisplayText] [nvarchar](255) NULL,
    [LanguageID] [int] NOT NULL,
    [Description] [nvarchar](4000) NULL,
 CONSTRAINT [PK_Discriminator] PRIMARY KEY CLUSTERED 
(
    [ID] ASC,
    [LanguageID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

1 个答案:

答案 0 :(得分:2)

一个更健全的对象模型将是

public class Triage
{
    public virtual Guid Id { get; set; }

    public virtual Discriminator SelectedDiscriminator { get; set; }

    // left out Equals and GetHashcode
}

public class Discriminator
{
    public Discriminator()
    {
        LocalizedTexts = new Dictionary<int, string>();
    }

    public virtual int Id { get; set; }
    public virtual string Name
    {
        get
        {
            switch (Id)
            {
                case 1:
                    return "Discriminator A";
                case 2:
                    return "Discriminator B";
                case 3:
                    return "Discriminator C";
                default:
                    return "Unknown";
            }
        }
    }
    public virtual IDictionary<int, LocalizedText> LocalizedTexts { get; protected set; }

    public override bool Equals(object obj)
    {
        var other = obj as Discriminator;

        return other != null && (Id == 0 ? ReferenceEquals(this, other) : Id == other.Id);
    }

    public override int GetHashCode()
    {
        return Id;
    }
}

public class LocalizedText
{
    public string DisplayName { get; set; }
    public string Description { get; set; }
}

带映射

public class TriageMap : ClassMap<Triage>
{
    public TriageMap()
    {
        Id(x => x.Id).GeneratedBy.GuidComb();

        References(x => x.SelectedDiscriminator, "SelectedDiscriminatorId");
    }
}

public class DiscriminatorMap : ClassMap<Discriminator>
{
    public DiscriminatorMap()
    {
        ReadOnly();
        SchemaExport.None();   // do not create Table for this. usefull for creating Schema for in memory unit-testing
        Table("Discriminators");
        Where("LanguageId = <some value all discriminators have>");
        Id(x => x.Id).GeneratedBy.Assigned();

        HasMany(x => x.LocalizedTexts)
            .Table("Discriminators")
            .KeyColumn("Id")
            .AsMap("LanguageId")
            .Component(c =>
            {
                c.Map(x => x.DisplayName);
                c.Map(x => x.Description);
            })
            .Cascade.AllDeleteOrphan()
            .Not.LazyLoad();
    }
}

唯一的缺点是sql看起来有点奇怪,因为NHibernate认为鉴别器本身就存在。