我想为我的一些实体创建一个基类,因为它们共享一个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...
为实体提供流畅的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<>.Add()
方法。我想要一个只读集合。将新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收到错误:
无法转换类型&#39; NHibernate.Collection.Generic.PersistentGenericBag&#39; 1 [SolutionDOC_Interface.Entity.Event]&#39;到了System.Collections.Generic.List&#39; 1 [SolutionDOC_Interface.Entity.Event]&#39;类型。
我认为它与EventRelatedEntity
类没有NHibernate映射这一事实有关,但我无法提供映射,因为它与数据库中的表没有关系。
也许如果我在不使用继承的情况下在每个类(公司,文档等)中声明事件列表,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();
}
// ...
}
答案 0 :(得分:1)
使用列表界面而不是具体列表类,然后Quillivant
的强制转换应该有效。
使用NHibernate.Collection.Generic.PersistentGenericBag
代替IList<Event>
,以便List<Event>
成为:
EventRelatedEntity