【问题标题】:Fluent NHibernate Correctly map readonly property from base classFluent NHibernate 正确映射基类中的只读属性
【发布时间】:2018-03-22 01:55:44
【问题描述】:

我想为我的一些实体创建一个基类,因为它们都共享一个Event 列表属性。 我还想让Event 列表只读属性

所以我创建了一个基础 EventRelatedEntity 类,然后在我的每个与事件有关的实体类上派生它。

还请注意,EventRelatedEntity 类没有 NHibernate 映射类,因为它没有链接到表。

参见下面的代码。

基类:

public class EventRelatedEntity
{
    private readonly List<Event> events;

    public virtual IReadOnlyCollection<Event> Events { get; protected set; }

    public EventRelatedEntity()
    {
        events = new List<Event>();
        Events = events.AsReadOnly();
    }

    protected virtual void AddEvent<T>(T entity, string message)
    {
        if (events == null)
            events = new List<Event>();

        Event newEvent = new Event();

        if (typeof(T) == typeof(Company))
        {
            newEvent.CompanyId = (entity as Company).Id;
            // ...and do some other stuff...
        }
        else if (typeof(T) == typeof(Document))
        {
            newEvent.DocumentId = (entity as Document).Id;
            // ...and do some other stuff...
        }
        else if (typeof(T) == typeof(Typology))
        {
            newEvent.TypologyId = (entity as Typology).Id;
            // ...and do some other stuff...
        }

        newEvent.Message = message;

        events.Add(newEvent);
    }
}

实体类

public class Company : EventRelatedEntity
{
    [Key]
    public virtual int Id { get; protected set; }
    [Required]
    public virtual string Alias { get; set; }
    [Required]
    public virtual string CompanyName { get; set; }
    // ...and some other properties...

    #region Actions

    public virtual void AddEvent(string message)
    {
        base.AddEvent(this, message);
    }

    #endregion
}

public class Document : EventRelatedEntity
{
    [Key]
    public override int Id { get; protected set; }
    [Required]
    public virtual User User { get; protected set; }
    // ...and some other properties...

    #region Actions

    public virtual void AddEvent(string message)
    {
        base.AddEvent(this, message);
    }

    #endregion
}

// ...and some other classes...

Fluent NHibernate 实体映射类

public class CompanyMap : ClassMap<Company>
{
    public CompanyMap()
    {
        Table("Companies");
        LazyLoad();
        Id(x => x.Id).GeneratedBy.Identity().Column("Id");
        Map(x => x.Alias).Column("Alias").Not.Nullable();
        Map(x => x.CompanyName).Column("CompanyName").Not.Nullable();
        // ...and some other mappings...

        // Link with Events table
        HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity)
            .KeyColumn("CompanyId")
            .Access.LowerCaseField()
            .Cascade.AllDeleteOrphan();
    }
}

public class DocumentMap : ClassMap<Document>
{   
    public DocumentMap()
    {
        Table("Documents");
        LazyLoad();
        Id(x => x.Id).GeneratedBy.Identity().Column("Id");
        References(x => x.User).Column("UserId");
        // ...and some other mappings...

        // Link with Events table
        HasMany(x => x.Events) // Events is declared in the base class (EventRelatedEntity)
            .KeyColumn("DocumentId")
            .Access.LowerCaseField()
            .Cascade.AllDeleteOrphan();
    }
}

// ...and some other mapping classes...

最后我想避免直接访问List&lt;&gt;.Add() 方法。我想要一个只读集合。将新的Event 添加到实体的Event 列表中的唯一方法必须是相应实体类的AddEvent 方法。

例子:

Document document = session.Get<Document>(1);
// ...the same for other derived classes...

// I WANT TO AVOID THIS!
document.Events.Add(new Event());
// WANTS TO BE THE ONLY PERMITTED WAY TO ADD NEW EVENTS
document.AddEvent("My new event message");

问题是当我这样做时:

Document document = session.Get<Document>(1);

我从 NHibernate 收到一个错误:

无法将“NHibernate.Collection.Generic.PersistentGenericBag'1 [SolutionDOC_Interface.Entity.Event]”类型的对象转换为“System.Collections.Generic.List'1 [SolutionDOC_Interface.Entity.Event]”类型。

我认为这与 EventRelatedEntity 类没有 NHibernate 映射的事实有关,但我无法提供映射,因为它与 DB 中的表无关。 也许如果我在每个类(公司、文档等)中声明事件列表而不使用继承,NHibernate 会起作用,但这种方法会产生很多我想避免的代码重复。

2017 年 10 月 18 日更新

像@ryan 建议的那样更改代码后,现在它可以工作了。

修改后的代码:

public class EventRelatedEntity
{
    private readonly IList<Event> events;

    public virtual IReadOnlyCollection<Event> Events { get; protected set; }

    public EventRelatedEntity()
    {
        events = new List<Event>();
        Events = (events as List<Event>).AsReadOnly();
    }

    // ...
}

【问题讨论】:

  • 那是什么问题?如果Events 确实被声明为IReadOnlyCollection,那么document.Events.Add(new Event()); 应该会产生错误:'IReadOnlyCollection&lt;Event&gt;' does not contain a definition for 'Add'...
  • 我收到 NHibernate 错误。我更新了问题。

标签: c# list nhibernate fluent-nhibernate readonly-collection


【解决方案1】:

使用列表接口而不是具体的列表类,那么NHibernate.Collection.Generic.PersistentGenericBag 的转换应该可以工作。

使用IList&lt;Event&gt; 而不是List&lt;Event&gt; 所以EventRelatedEntity 变为:

public class EventRelatedEntity
{
    private readonly IList<Event> events;

    // rest of implementation...
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 2010-10-28
    • 2011-08-31
    • 1970-01-01
    相关资源
    最近更新 更多