我想为我的一些实体创建一个基类,因为它们都共享一个Event
列表属性。 我也想使Event
列表只读属性。流利NHibernate正确地将只读属性映射到基类
所以我创建了一个基类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的一个错误:
Cannot cast objects of type 'NHibernate.Collection.Generic.PersistentGenericBag'1 [SolutionDOC_Interface.Entity.Event]' to the 'System.Collections.Generic.List'1 [SolutionDOC_Interface.Entity.Event]' type.
,我认为它是与相关实际上EventRelatedEntity
类没有NHibernate映射,但我无法提供映射,因为它没有d o用DB中的表格。 也许如果我在每个类(公司,文档等)内部声明事件列表而不使用继承,NHibernate就可以工作,但是这种方法会产生很多我想避免的代码重复。
UPDATE 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''不包含'Add'的定义。 。' –
ryan
我得到一个NHibernate错误。我更新了这个问题。 –